changeset 1205:6009c59d8676 broker

fix to sdl
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 02 Dec 2019 14:32:05 +0100
parents b519c1c878f1
children 17a92c39c633
files Framework/OpenGL/SdlOpenGLContext.h Framework/Scene2D/Internals/CompositorHelper.cpp Framework/Viewport/IViewport.h Framework/Viewport/SdlViewport.cpp Framework/Viewport/SdlViewport.h Framework/Viewport/SdlWindow.cpp Framework/Viewport/SdlWindow.h Framework/Viewport/ViewportBase.cpp Framework/Viewport/ViewportBase.h
diffstat 9 files changed, 150 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/Framework/OpenGL/SdlOpenGLContext.h	Fri Nov 29 21:24:29 2019 +0100
+++ b/Framework/OpenGL/SdlOpenGLContext.h	Mon Dec 02 14:32:05 2019 +0100
@@ -64,6 +64,11 @@
     virtual unsigned int GetCanvasWidth() const ORTHANC_OVERRIDE;
 
     virtual unsigned int GetCanvasHeight() const ORTHANC_OVERRIDE;
+
+    void ToggleMaximize()
+    {
+      window_.ToggleMaximize();
+    }
   };
 }
 
--- a/Framework/Scene2D/Internals/CompositorHelper.cpp	Fri Nov 29 21:24:29 2019 +0100
+++ b/Framework/Scene2D/Internals/CompositorHelper.cpp	Mon Dec 02 14:32:05 2019 +0100
@@ -115,7 +115,7 @@
       {
         // This layer has already been rendered
         assert(found->second->GetLastRevision() <= layer.GetRevision());
-        
+
         if (found->second->GetLastRevision() < layer.GetRevision())
         {
           found->second->UpdateRenderer();
--- a/Framework/Viewport/IViewport.h	Fri Nov 29 21:24:29 2019 +0100
+++ b/Framework/Viewport/IViewport.h	Mon Dec 02 14:32:05 2019 +0100
@@ -54,13 +54,23 @@
       virtual bool HasCompositor() const = 0;
 
       virtual ICompositor& GetCompositor() = 0;
+
+      virtual void FitContent() = 0;
     };   
     
     virtual ~IViewport()
     {
     }
 
-    virtual void Refresh() = 0;
+    // Can be invoked from any thread (notably from the thread of the
+    // Stone context)
+    virtual void Invalidate() = 0;
+
+    // Must be invoked from the main (GUI) thread
+    virtual void Paint() = 0;
+
+    virtual void UpdateSize(unsigned int width,
+                            unsigned int height) = 0;
 
     virtual ILock* Lock() = 0;
   };
--- a/Framework/Viewport/SdlViewport.cpp	Fri Nov 29 21:24:29 2019 +0100
+++ b/Framework/Viewport/SdlViewport.cpp	Mon Dec 02 14:32:05 2019 +0100
@@ -24,6 +24,26 @@
 
 namespace OrthancStone
 {
+  SdlViewport::SdlViewport()
+  {
+    refreshEvent_ = SDL_RegisterEvents(1);
+    
+    if (refreshEvent_ == static_cast<uint32_t>(-1))
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+    }
+  }
+
+
+  void SdlViewport::SendRefreshEvent()
+  {
+    SDL_Event event;
+    SDL_memset(&event, 0, sizeof(event));
+    event.type = refreshEvent_;
+    SDL_PushEvent(&event);  // This function is thread-safe, and can be called from other threads safely.
+  }
+
+  
   SdlOpenGLViewport::SdlOpenGLViewport(const char* title,
                                        unsigned int width,
                                        unsigned int height,
@@ -33,7 +53,12 @@
     compositor_.reset(new OpenGLCompositor(context_, GetScene()));
   }
 
-  void SdlOpenGLViewport::Refresh()
+  void SdlOpenGLViewport::Invalidate()
+  {
+    SendRefreshEvent();
+  }
+
+  void SdlOpenGLViewport::Paint()
   {
     boost::mutex::scoped_lock lock(mutex_);
     compositor_->Refresh();
@@ -45,9 +70,9 @@
                                      unsigned int height,
                                      bool allowDpiScaling) :
     window_(title, width, height, false /* enable OpenGL */, allowDpiScaling),
-    compositor_(GetScene(), width, height)
+    compositor_(GetScene(), width, height),
+    sdlSurface_(NULL)
   {
-    UpdateSdlSurfaceSize(width, height);
   }
 
   SdlCairoViewport::~SdlCairoViewport()
@@ -58,16 +83,30 @@
     }
   }
   
-  void SdlCairoViewport::RefreshInternal()  // Assumes that the mutex is locked
+  void SdlCairoViewport::InvalidateInternal()  // Assumes that the mutex is locked
   {
     compositor_.Refresh();
-    window_.Render(sdlSurface_);
+    CreateSdlSurfaceFromCompositor();
   }
 
-  void SdlCairoViewport::Refresh()
+  void SdlCairoViewport::Paint()
   {
     boost::mutex::scoped_lock lock(mutex_);
-    RefreshInternal();
+    
+    if (sdlSurface_ != NULL)
+    {
+      window_.Render(sdlSurface_);
+    }    
+  }
+
+  void SdlCairoViewport::Invalidate()
+  {
+    {
+      boost::mutex::scoped_lock lock(mutex_);
+      InvalidateInternal();
+    }
+
+    SendRefreshEvent();
   }
 
   void SdlCairoViewport::UpdateSize(unsigned int width,
@@ -75,17 +114,34 @@
   {
     boost::mutex::scoped_lock lock(mutex_);
     compositor_.UpdateSize(width, height);
-    UpdateSdlSurfaceSize(width, height);
-    RefreshInternal();
+    InvalidateInternal();
   }
   
-  void SdlCairoViewport::UpdateSdlSurfaceSize(unsigned int width,
-                                              unsigned int height)  // Assumes that the mutex is locked
+  void SdlCairoViewport::CreateSdlSurfaceFromCompositor()  // Assumes that the mutex is locked
   {
     static const uint32_t rmask = 0x00ff0000;
     static const uint32_t gmask = 0x0000ff00;
     static const uint32_t bmask = 0x000000ff;
 
+    const unsigned int width = compositor_.GetCanvas().GetWidth();
+    const unsigned int height = compositor_.GetCanvas().GetHeight();
+    
+    if (sdlSurface_ != NULL)
+    {
+      if (sdlSurface_->pixels == compositor_.GetCanvas().GetBuffer() &&
+          sdlSurface_->w == static_cast<int>(width) &&
+          sdlSurface_->h == static_cast<int>(height) &&
+          sdlSurface_->pitch == static_cast<int>(compositor_.GetCanvas().GetPitch()))
+      {
+        // The image from the compositor has not changed, no need to update the surface
+        return;
+      }
+      else
+      {
+        SDL_FreeSurface(sdlSurface_);
+      }
+    }
+
     sdlSurface_ = SDL_CreateRGBSurfaceFrom((void*)(compositor_.GetCanvas().GetBuffer()), width, height, 32,
                                            compositor_.GetCanvas().GetPitch(), rmask, gmask, bmask, 0);
     if (!sdlSurface_)
--- a/Framework/Viewport/SdlViewport.h	Fri Nov 29 21:24:29 2019 +0100
+++ b/Framework/Viewport/SdlViewport.h	Mon Dec 02 14:32:05 2019 +0100
@@ -41,27 +41,38 @@
 #include "../Scene2D/CairoCompositor.h"
 #include "ViewportBase.h"
 
+#include <SDL_events.h>
+
 namespace OrthancStone
 {
   class SdlViewport : public ViewportBase
   {
-  protected:
-    boost::mutex  mutex_;
+  private:
+    uint32_t  refreshEvent_;
 
+  protected:
+    void SendRefreshEvent();
+    
   public:
-    SdlViewport()
+    SdlViewport();
+
+    bool IsRefreshEvent(const SDL_Event& event) const
     {
+      return (event.type == refreshEvent_);
     }
 
     virtual void UpdateSize(unsigned int width,
                             unsigned int height) = 0;
+
+    virtual void ToggleMaximize() = 0;
   };
 
 
   class SdlOpenGLViewport : public SdlViewport
   {
   private:
-    SdlOpenGLContext  context_;
+    boost::mutex                     mutex_;
+    SdlOpenGLContext                 context_;
     std::auto_ptr<OpenGLCompositor>  compositor_;
 
     class SdlLock : public LockBase
@@ -95,7 +106,9 @@
                       unsigned int height,
                       bool allowDpiScaling = true);
 
-    virtual void Refresh() ORTHANC_OVERRIDE;
+    virtual void Invalidate() ORTHANC_OVERRIDE;
+
+    virtual void Paint() ORTHANC_OVERRIDE;
 
     virtual ILock* Lock() ORTHANC_OVERRIDE
     {
@@ -106,6 +119,12 @@
     {
       // nothing to do in OpenGL, the OpenGLCompositor::UpdateSize will be called automatically
     }
+
+    virtual void ToggleMaximize() ORTHANC_OVERRIDE
+    {
+      boost::mutex::scoped_lock lock(mutex_);
+      context_.ToggleMaximize();
+    }
   };
 
 
@@ -137,14 +156,14 @@
       }
     };
  
+    boost::mutex      mutex_;
     SdlWindow         window_;
     CairoCompositor   compositor_;
     SDL_Surface*      sdlSurface_;
 
-    void RefreshInternal();
+    void InvalidateInternal();
     
-    void UpdateSdlSurfaceSize(unsigned int width,
-                              unsigned int height);
+    void CreateSdlSurfaceFromCompositor();
 
   public:
     SdlCairoViewport(const char* title,
@@ -154,9 +173,22 @@
 
     ~SdlCairoViewport();
 
-    virtual void Refresh() ORTHANC_OVERRIDE;
+    virtual void Invalidate() ORTHANC_OVERRIDE;
+
+    virtual void Paint() ORTHANC_OVERRIDE;
+
+    virtual ILock* Lock() ORTHANC_OVERRIDE
+    {
+      return new SdlLock(*this);
+    }
 
     virtual void UpdateSize(unsigned int width,
                             unsigned int height) ORTHANC_OVERRIDE;
+
+    virtual void ToggleMaximize() ORTHANC_OVERRIDE
+    {
+      boost::mutex::scoped_lock lock(mutex_);
+      window_.ToggleMaximize();
+    }
   };
 }
--- a/Framework/Viewport/SdlWindow.cpp	Fri Nov 29 21:24:29 2019 +0100
+++ b/Framework/Viewport/SdlWindow.cpp	Mon Dec 02 14:32:05 2019 +0100
@@ -156,7 +156,14 @@
 
   void SdlWindow::Render(SDL_Surface* surface)
   {
-    //SDL_RenderClear(renderer_);
+    /**
+     * "You are strongly encouraged to call SDL_RenderClear() to
+     * initialize the backbuffer before starting each new frame's
+     * drawing, even if you plan to overwrite every pixel."
+     * https://wiki.libsdl.org/SDL_RenderPresent
+     **/
+    SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 255);
+    SDL_RenderClear(renderer_);  // Clear the entire screen to our selected color
 
     SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer_, surface);
     if (texture != NULL)
--- a/Framework/Viewport/SdlWindow.h	Fri Nov 29 21:24:29 2019 +0100
+++ b/Framework/Viewport/SdlWindow.h	Mon Dec 02 14:32:05 2019 +0100
@@ -58,6 +58,11 @@
 
     unsigned int GetHeight() const;
 
+    /**
+     * WARNING: "Refresh()" cannot only be called from the main SDL
+     * thread, in which the window was created. Otherwise, the
+     * renderer displays nothing!
+     **/
     void Render(struct SDL_Surface* surface);
 
     void ToggleMaximize();
--- a/Framework/Viewport/ViewportBase.cpp	Fri Nov 29 21:24:29 2019 +0100
+++ b/Framework/Viewport/ViewportBase.cpp	Mon Dec 02 14:32:05 2019 +0100
@@ -40,4 +40,14 @@
       return ScenePoint2D(0, 0);
     }
   }
+
+
+  void ViewportBase::LockBase::FitContent()
+  {
+    if (HasCompositor())
+    {
+      ICompositor& compositor = GetCompositor();
+      GetScene().FitContent(compositor.GetCanvasWidth(), compositor.GetCanvasHeight());
+    }
+  }
 }
--- a/Framework/Viewport/ViewportBase.h	Fri Nov 29 21:24:29 2019 +0100
+++ b/Framework/Viewport/ViewportBase.h	Mon Dec 02 14:32:05 2019 +0100
@@ -49,6 +49,8 @@
       }
 
       virtual ScenePoint2D GetPixelCenterCoordinates(int x, int y) ORTHANC_OVERRIDE;
+
+      virtual void FitContent() ORTHANC_OVERRIDE;
     };
 
     Scene2D& GetScene()