changeset 56:9e3c2e75b870 wasm

extremely simplified SDL engine
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 28 Apr 2017 21:46:41 +0200
parents f0f354a97581
children d20e25cfcf3a
files Applications/BinarySemaphore.cpp Applications/BinarySemaphore.h Applications/Sdl/SdlBuffering.cpp Applications/Sdl/SdlBuffering.h Applications/Sdl/SdlEngine.cpp Applications/Sdl/SdlEngine.h Resources/CMake/OrthancStone.cmake Resources/Graveyard/Threading/BinarySemaphore.cpp Resources/Graveyard/Threading/BinarySemaphore.h Resources/Graveyard/Threading/SdlBuffering.cpp Resources/Graveyard/Threading/SdlBuffering.h
diffstat 11 files changed, 313 insertions(+), 393 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/BinarySemaphore.cpp	Fri Apr 28 17:24:18 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "BinarySemaphore.h"
-
-namespace OrthancStone
-{
-  BinarySemaphore::BinarySemaphore() : 
-    proceed_(false)
-  {
-  }
-
-  void BinarySemaphore::Signal()
-  {
-    //boost::mutex::scoped_lock lock(mutex_);
-
-    proceed_ = true;
-    condition_.notify_one(); 
-  }
-
-  void BinarySemaphore::Wait()
-  {
-    boost::mutex::scoped_lock lock(mutex_);
-
-    while (!proceed_)
-    {
-      condition_.wait(lock);
-    }
-
-    proceed_ = false;
-  }
-}
--- a/Applications/BinarySemaphore.h	Fri Apr 28 17:24:18 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include <boost/thread/mutex.hpp>
-#include <boost/thread/condition.hpp>
-
-namespace OrthancStone
-{
-  class BinarySemaphore : public boost::noncopyable
-  {
-  private:
-    bool proceed_;
-    boost::mutex mutex_;
-    boost::condition_variable condition_;
-
-  public:
-    explicit BinarySemaphore();
-
-    void Signal();
-
-    void Wait();
-  };
-}
--- a/Applications/Sdl/SdlBuffering.cpp	Fri Apr 28 17:24:18 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,134 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "SdlBuffering.h"
-
-#if ORTHANC_ENABLE_SDL == 1
-
-#include "../../../Resources/Orthanc/Core/Logging.h"
-#include "../../../Resources/Orthanc/Core/OrthancException.h"
-
-namespace OrthancStone
-{
-  SdlBuffering::SdlBuffering() :
-    sdlSurface_(NULL),
-    pendingFrame_(false)
-  {
-  }
-
-
-  SdlBuffering::~SdlBuffering()
-  {
-    if (sdlSurface_)
-    {
-      SDL_FreeSurface(sdlSurface_);
-    }
-  }
-
-
-  void SdlBuffering::SetSize(unsigned int width,
-                             unsigned int height,
-                             IViewport& viewport)
-  {
-    boost::mutex::scoped_lock lock(mutex_);
-
-    viewport.SetSize(width, height);
-
-    if (offscreenSurface_.get() == NULL ||
-        offscreenSurface_->GetWidth() != width ||
-        offscreenSurface_->GetHeight() != height)
-    {
-      offscreenSurface_.reset(new CairoSurface(width, height));
-    }
-
-    if (onscreenSurface_.get() == NULL ||
-        onscreenSurface_->GetWidth() != width ||
-        onscreenSurface_->GetHeight() != height)
-    {
-      onscreenSurface_.reset(new CairoSurface(width, height));
-
-      // TODO Big endian?
-      static const uint32_t rmask = 0x00ff0000;
-      static const uint32_t gmask = 0x0000ff00;
-      static const uint32_t bmask = 0x000000ff;
-
-      if (sdlSurface_)
-      {
-        SDL_FreeSurface(sdlSurface_);
-      }
-
-      sdlSurface_ = SDL_CreateRGBSurfaceFrom(onscreenSurface_->GetBuffer(), width, height, 32,
-                                             onscreenSurface_->GetPitch(), rmask, gmask, bmask, 0);
-      if (!sdlSurface_)
-      {
-        LOG(ERROR) << "Cannot create a SDL surface from a Cairo surface";
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-      }    
-    }
-
-    pendingFrame_ = false;
-  }
-
-
-  bool SdlBuffering::RenderOffscreen(IViewport& viewport)
-  {
-    boost::mutex::scoped_lock lock(mutex_);
-
-    if (offscreenSurface_.get() == NULL)
-    {
-      return false;
-    }
-
-    Orthanc::ImageAccessor target = offscreenSurface_->GetAccessor();
-
-    if (viewport.Render(target) &&
-        !pendingFrame_)
-    {
-      pendingFrame_ = true;
-      return true;
-    }
-    else
-    {
-      return false;
-    }
-  }
-
-
-  void SdlBuffering::SwapToScreen(SdlWindow& window)
-  {
-    if (!pendingFrame_ ||
-        offscreenSurface_.get() == NULL ||
-        onscreenSurface_.get() == NULL)
-    {
-      return;
-    }
-
-    {
-      boost::mutex::scoped_lock lock(mutex_);
-      onscreenSurface_->Copy(*offscreenSurface_);
-    }
-    
-    window.Render(sdlSurface_);
-    pendingFrame_ = false;
-  }
-}
-
-#endif
--- a/Applications/Sdl/SdlBuffering.h	Fri Apr 28 17:24:18 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#if ORTHANC_ENABLE_SDL == 1
-
-#include "SdlWindow.h"
-#include "../../Framework/Viewport/CairoSurface.h"
-#include "../../Framework/Viewport/IViewport.h"
-
-#include <boost/thread/mutex.hpp>
-
-namespace OrthancStone
-{
-  class SdlBuffering : public boost::noncopyable
-  {
-  private:
-    boost::mutex                 mutex_;
-    std::auto_ptr<CairoSurface>  offscreenSurface_;
-    std::auto_ptr<CairoSurface>  onscreenSurface_;
-    SDL_Surface*                 sdlSurface_;
-    bool                         pendingFrame_;
-
-  public:
-    SdlBuffering();
-
-    ~SdlBuffering();
-
-    void SetSize(unsigned int width,
-                 unsigned int height,
-                 IViewport& viewport);
-
-    // Returns "true" if a new refresh of the display should be
-    // triggered afterwards
-    bool RenderOffscreen(IViewport& viewport);
-
-    void SwapToScreen(SdlWindow& window);
-  };
-}
-
-#endif
--- a/Applications/Sdl/SdlEngine.cpp	Fri Apr 28 17:24:18 2017 +0200
+++ b/Applications/Sdl/SdlEngine.cpp	Fri Apr 28 21:46:41 2017 +0200
@@ -29,55 +29,27 @@
 
 namespace OrthancStone
 {
+  void SdlEngine::SetSize(BasicApplicationContext::ViewportLocker& locker,
+                          unsigned int width,
+                          unsigned int height)
+  {
+    locker.GetViewport().SetSize(width, height);
+    surface_.SetSize(width, height);
+  }
+    
+
   void SdlEngine::RenderFrame()
   {
-    if (!viewportChanged_)
-    {
-      return;
-    }
-
-    viewportChanged_ = false;
-
-    bool updated;
-    
+    if (viewportChanged_)
     {
       BasicApplicationContext::ViewportLocker locker(context_);
-      updated = buffering_.RenderOffscreen(locker.GetViewport());
-    }
+      surface_.Render(locker.GetViewport());
 
-    if (updated)
-    {
-      // Do not notify twice when a new frame was rendered, to avoid
-      // spoiling the SDL event queue
-      SDL_Event event;
-      SDL_memset(&event, 0, sizeof(event));
-      event.type = refreshEvent_;
-      event.user.code = 0;
-      event.user.data1 = 0;
-      event.user.data2 = 0;
-      SDL_PushEvent(&event);
+      viewportChanged_ = false;
     }
   }
 
 
-  void SdlEngine::RenderThread(SdlEngine* that)
-  {
-    for (;;)
-    {
-      that->renderFrame_.Wait();
-
-      if (that->continue_)
-      {
-        that->RenderFrame();
-      }
-      else
-      {
-        return;
-      }
-    }
-  }             
-
-
   KeyboardModifiers SdlEngine::GetKeyboardModifiers(const uint8_t* keyboardState,
                                                     const int scancodeCount)
   {
@@ -126,55 +98,23 @@
   }
 
 
-  void SdlEngine::SetSize(BasicApplicationContext::ViewportLocker& locker,
-                          unsigned int width,
-                          unsigned int height)
-  {
-    buffering_.SetSize(width, height, locker.GetViewport());
-    viewportChanged_ = true;
-    Refresh();
-  }
-
-
-  void SdlEngine::Stop()
-  {
-    if (continue_)
-    {
-      continue_ = false;
-      renderFrame_.Signal();  // Unlock the render thread
-      renderThread_.join();
-    }
-  }
-
-
-  void SdlEngine::Refresh()
-  {
-    renderFrame_.Signal();
-  }
-
-
   SdlEngine::SdlEngine(SdlWindow& window,
                        BasicApplicationContext& context) :
     window_(window),
     context_(context),
-    continue_(true)
+    surface_(window),
+    viewportChanged_(true)
   {
-    refreshEvent_ = SDL_RegisterEvents(1);
-
     {
       BasicApplicationContext::ViewportLocker locker(context_);
       SetSize(locker, window_.GetWidth(), window_.GetHeight());
       locker.GetViewport().Register(*this);
     }
-
-    renderThread_ = boost::thread(RenderThread, this);
   }
   
 
   SdlEngine::~SdlEngine()
   {
-    Stop();
-
     {
       BasicApplicationContext::ViewportLocker locker(context_);
       locker.GetViewport().Unregister(*this);
@@ -190,11 +130,12 @@
     bool stop = false;
     while (!stop)
     {
-      Refresh();
+      RenderFrame();
 
       SDL_Event event;
 
-      while (SDL_PollEvent(&event))
+      while (!stop &&
+             SDL_PollEvent(&event))
       {
         BasicApplicationContext::ViewportLocker locker(context_);
 
@@ -203,10 +144,6 @@
           stop = true;
           break;
         }
-        else if (event.type == refreshEvent_)
-        {
-          buffering_.SwapToScreen(window_);
-        }
         else if (event.type == SDL_MOUSEBUTTONDOWN)
         {
           KeyboardModifiers modifiers = GetKeyboardModifiers(keyboardState, scancodeCount);
@@ -273,7 +210,8 @@
             locker.GetViewport().MouseWheel(MouseWheelDirection_Down, x, y, modifiers);
           }
         }
-        else if (event.type == SDL_KEYDOWN)
+        else if (event.type == SDL_KEYDOWN &&
+                 event.key.repeat == 0 /* Ignore key bounce */)
         {
           KeyboardModifiers modifiers = GetKeyboardModifiers(keyboardState, scancodeCount);
 
@@ -311,11 +249,7 @@
           }
         }
       }
-
-      SDL_Delay(10);   // Necessary for mouse wheel events to work
     }
-
-    Stop();
   }
 
 
--- a/Applications/Sdl/SdlEngine.h	Fri Apr 28 17:24:18 2017 +0200
+++ b/Applications/Sdl/SdlEngine.h	Fri Apr 28 21:46:41 2017 +0200
@@ -23,12 +23,9 @@
 
 #if ORTHANC_ENABLE_SDL == 1
 
-#include "SdlBuffering.h"
-#include "../BinarySemaphore.h"
+#include "SdlSurface.h"
 #include "../BasicApplicationContext.h"
 
-#include <boost/thread.hpp>
-
 namespace OrthancStone
 {
   class SdlEngine : public IViewport::IChangeObserver
@@ -36,27 +33,17 @@
   private:
     SdlWindow&                window_;
     BasicApplicationContext&  context_;
-    SdlBuffering              buffering_;
-    boost::thread             renderThread_;
-    bool                      continue_;
-    BinarySemaphore           renderFrame_;
-    uint32_t                  refreshEvent_;
+    SdlSurface                surface_;
     bool                      viewportChanged_;
 
-    void RenderFrame();
-
-    static void RenderThread(SdlEngine* that);
-
-    static KeyboardModifiers GetKeyboardModifiers(const uint8_t* keyboardState,
-                                                  const int scancodeCount);
-
     void SetSize(BasicApplicationContext::ViewportLocker& locker,
                  unsigned int width,
                  unsigned int height);
+    
+    void RenderFrame();
 
-    void Stop();
-
-    void Refresh();
+    static KeyboardModifiers GetKeyboardModifiers(const uint8_t* keyboardState,
+                                                  const int scancodeCount);
 
   public:
     SdlEngine(SdlWindow& window,
--- a/Resources/CMake/OrthancStone.cmake	Fri Apr 28 17:24:18 2017 +0200
+++ b/Resources/CMake/OrthancStone.cmake	Fri Apr 28 21:46:41 2017 +0200
@@ -177,10 +177,9 @@
 
 list(APPEND ORTHANC_STONE_SOURCES
   ${ORTHANC_STONE_DIR}/Applications/BasicApplicationContext.cpp
-  ${ORTHANC_STONE_DIR}/Applications/BinarySemaphore.cpp
   ${ORTHANC_STONE_DIR}/Applications/IBasicApplication.cpp
-  ${ORTHANC_STONE_DIR}/Applications/Sdl/SdlBuffering.cpp
   ${ORTHANC_STONE_DIR}/Applications/Sdl/SdlEngine.cpp
+  ${ORTHANC_STONE_DIR}/Applications/Sdl/SdlSurface.cpp
   ${ORTHANC_STONE_DIR}/Applications/Sdl/SdlWindow.cpp
 
   ${ORTHANC_STONE_DIR}/Framework/Layers/CircleMeasureTracker.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Graveyard/Threading/BinarySemaphore.cpp	Fri Apr 28 21:46:41 2017 +0200
@@ -0,0 +1,50 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017 Osimis, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "BinarySemaphore.h"
+
+namespace OrthancStone
+{
+  BinarySemaphore::BinarySemaphore() : 
+    proceed_(false)
+  {
+  }
+
+  void BinarySemaphore::Signal()
+  {
+    //boost::mutex::scoped_lock lock(mutex_);
+
+    proceed_ = true;
+    condition_.notify_one(); 
+  }
+
+  void BinarySemaphore::Wait()
+  {
+    boost::mutex::scoped_lock lock(mutex_);
+
+    while (!proceed_)
+    {
+      condition_.wait(lock);
+    }
+
+    proceed_ = false;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Graveyard/Threading/BinarySemaphore.h	Fri Apr 28 21:46:41 2017 +0200
@@ -0,0 +1,43 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017 Osimis, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition.hpp>
+
+namespace OrthancStone
+{
+  class BinarySemaphore : public boost::noncopyable
+  {
+  private:
+    bool proceed_;
+    boost::mutex mutex_;
+    boost::condition_variable condition_;
+
+  public:
+    explicit BinarySemaphore();
+
+    void Signal();
+
+    void Wait();
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Graveyard/Threading/SdlBuffering.cpp	Fri Apr 28 21:46:41 2017 +0200
@@ -0,0 +1,134 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017 Osimis, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "SdlBuffering.h"
+
+#if ORTHANC_ENABLE_SDL == 1
+
+#include "../../../Resources/Orthanc/Core/Logging.h"
+#include "../../../Resources/Orthanc/Core/OrthancException.h"
+
+namespace OrthancStone
+{
+  SdlBuffering::SdlBuffering() :
+    sdlSurface_(NULL),
+    pendingFrame_(false)
+  {
+  }
+
+
+  SdlBuffering::~SdlBuffering()
+  {
+    if (sdlSurface_)
+    {
+      SDL_FreeSurface(sdlSurface_);
+    }
+  }
+
+
+  void SdlBuffering::SetSize(unsigned int width,
+                             unsigned int height,
+                             IViewport& viewport)
+  {
+    boost::mutex::scoped_lock lock(mutex_);
+
+    viewport.SetSize(width, height);
+
+    if (offscreenSurface_.get() == NULL ||
+        offscreenSurface_->GetWidth() != width ||
+        offscreenSurface_->GetHeight() != height)
+    {
+      offscreenSurface_.reset(new CairoSurface(width, height));
+    }
+
+    if (onscreenSurface_.get() == NULL ||
+        onscreenSurface_->GetWidth() != width ||
+        onscreenSurface_->GetHeight() != height)
+    {
+      onscreenSurface_.reset(new CairoSurface(width, height));
+
+      // TODO Big endian?
+      static const uint32_t rmask = 0x00ff0000;
+      static const uint32_t gmask = 0x0000ff00;
+      static const uint32_t bmask = 0x000000ff;
+
+      if (sdlSurface_)
+      {
+        SDL_FreeSurface(sdlSurface_);
+      }
+
+      sdlSurface_ = SDL_CreateRGBSurfaceFrom(onscreenSurface_->GetBuffer(), width, height, 32,
+                                             onscreenSurface_->GetPitch(), rmask, gmask, bmask, 0);
+      if (!sdlSurface_)
+      {
+        LOG(ERROR) << "Cannot create a SDL surface from a Cairo surface";
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+      }    
+    }
+
+    pendingFrame_ = false;
+  }
+
+
+  bool SdlBuffering::RenderOffscreen(IViewport& viewport)
+  {
+    boost::mutex::scoped_lock lock(mutex_);
+
+    if (offscreenSurface_.get() == NULL)
+    {
+      return false;
+    }
+
+    Orthanc::ImageAccessor target = offscreenSurface_->GetAccessor();
+
+    if (viewport.Render(target) &&
+        !pendingFrame_)
+    {
+      pendingFrame_ = true;
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+
+  void SdlBuffering::SwapToScreen(SdlWindow& window)
+  {
+    if (!pendingFrame_ ||
+        offscreenSurface_.get() == NULL ||
+        onscreenSurface_.get() == NULL)
+    {
+      return;
+    }
+
+    {
+      boost::mutex::scoped_lock lock(mutex_);
+      onscreenSurface_->Copy(*offscreenSurface_);
+    }
+    
+    window.Render(sdlSurface_);
+    pendingFrame_ = false;
+  }
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Graveyard/Threading/SdlBuffering.h	Fri Apr 28 21:46:41 2017 +0200
@@ -0,0 +1,60 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017 Osimis, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#if ORTHANC_ENABLE_SDL == 1
+
+#include "SdlWindow.h"
+#include "../../Framework/Viewport/CairoSurface.h"
+#include "../../Framework/Viewport/IViewport.h"
+
+#include <boost/thread/mutex.hpp>
+
+namespace OrthancStone
+{
+  class SdlBuffering : public boost::noncopyable
+  {
+  private:
+    boost::mutex                 mutex_;
+    std::auto_ptr<CairoSurface>  offscreenSurface_;
+    std::auto_ptr<CairoSurface>  onscreenSurface_;
+    SDL_Surface*                 sdlSurface_;
+    bool                         pendingFrame_;
+
+  public:
+    SdlBuffering();
+
+    ~SdlBuffering();
+
+    void SetSize(unsigned int width,
+                 unsigned int height,
+                 IViewport& viewport);
+
+    // Returns "true" if a new refresh of the display should be
+    // triggered afterwards
+    bool RenderOffscreen(IViewport& viewport);
+
+    void SwapToScreen(SdlWindow& window);
+  };
+}
+
+#endif