[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    playground/base/plasma/wallpapers/mandelbrot
From:       Benoît Jacob <jacob.benoit.1 () gmail ! com>
Date:       2009-04-04 14:39:42
Message-ID: 1238855982.390715.22376.nullmailer () svn ! kde ! org
[Download RAW message or body]

SVN commit 949120 by bjacob:

finally, giving love to the mandelbrot plugin.
* big reorganization, splitting into smaller files, etc
* on x86(32bit), compile both paths and detect SSE2 at runtime using Solid
* on other architectures, compile only the path with the arch defaults,
  while the other remains just a skeleton



 M  +38 -5     CMakeLists.txt  
 A             detectSSE2.cpp   [License: GPL (v2/3)]
 A             global.h   [License: GPL (v2/3)]
 M  +9 -128    mandelbrot.cpp  
 M  +8 -37     mandelbrot.h  
 M  +7 -5      render.h  
 M  +18 -4     render_impl.cpp  
 M  +1 -1      render_impl.h  
 AM            render_with_SSE2_explicitly_enabled_if_x86.cpp   \
render_with_vectorization.cpp#948158 [License: UNKNOWN]  AM            \
render_with_arch_defaults.cpp   render_without_vectorization.cpp#948158 [License: \
Trivial file.]  D             render_with_vectorization.cpp  
 D             render_without_vectorization.cpp  
 AM            renderthread.cpp   mandelbrot.cpp#948158 [License: GPL (v2/3)]
 AM            renderthread.h   mandelbrot.h#948158 [License: GPL (v2/3)]
 AM            tile.cpp   mandelbrot.cpp#948158 [License: GPL (v2/3)]
 AM            tile.h   mandelbrot.h#948158 [License: GPL (v2/3)]


--- trunk/playground/base/plasma/wallpapers/mandelbrot/CMakeLists.txt #949119:949120
@@ -3,21 +3,54 @@
 
 if(EIGEN2_FOUND)
 
+
 project(plasma-wallpaper-mandelbrot)
 
 include_directories(${EIGEN2_INCLUDE_DIR})
 
-set(CMAKE_CXX_FLAGS "-O2 -DEIGEN_NO_DEBUG -msse2 ${CMAKE_CXX_FLAGS}")
-
 set(mandelbrot_SRCS
     mandelbrot.cpp
-    render_with_vectorization.cpp
-    render_without_vectorization.cpp
+    tile.cpp
+    renderthread.cpp
+    render_with_arch_defaults.cpp
+    render_with_SSE2_explicitly_enabled_if_x86.cpp
+    detectSSE2.cpp
 )
 kde4_add_ui_files(mandelbrot_SRCS config.ui)
 
+# The x86-specific stuff below does not mean that this code is non-portable!
+# The idea is that x86 (32bit) is the ONLY major architecture on which vectorization \
(SSE2) may or may not be available. +# Other platforms have either ALWAYS \
vectorization (x86-64, PPC...) or NEVER in which case Eigen takes care of the \
details. +# Only on x86 do we have to take special care to compile 2 paths, one with \
SSE and one without, and choose the right one at runtime. +
+# MANDELBROT_ON_X86 will be non-empty if the CPU name contains "86" which we only \
use to make sure we may ask the +# compiler to enable SSE. At this stage we don't \
tell the difference between x86 and X86-64, and for 64bit CPUs, +# we don't know if \
we're in 32bit or 64bit mode. That will be done in the source code using preprocessor \
symbols. +string(REGEX MATCH "86" MANDELBROT_ON_X86 "${CMAKE_SYSTEM_PROCESSOR}")
+if(MANDELBROT_ON_X86)
+  if(CMAKE_COMPILER_IS_GNUCXX)
+    set(SSE2_CXX_FLAG "-msse2")
+  elseif(MSVC)
+    set(SSE2_CXX_FLAG "/arch:SSE2")
+  else(CMAKE_COMPILER_IS_GNUCXX)
+    set(SSE2_CXX_FLAG "")
+  endif(CMAKE_COMPILER_IS_GNUCXX)
+endif(MANDELBROT_ON_X86)
+#that's all, we don't use MANDELBROT_ON_X86 anymore
+
+
+set_source_files_properties(
+  render_with_arch_defaults.cpp
+  PROPERTIES COMPILE_FLAGS "-O2 -DEIGEN_NO_DEBUG"
+)
+
+set_source_files_properties(
+  render_with_SSE2_explicitly_enabled_if_x86.cpp
+  PROPERTIES COMPILE_FLAGS "-O2 -DEIGEN_NO_DEBUG ${SSE2_CXX_FLAG}"
+)
+
 kde4_add_plugin(plasma_wallpaper_mandelbrot ${mandelbrot_SRCS})
-target_link_libraries(plasma_wallpaper_mandelbrot ${KDE4_PLASMA_LIBS} \
${KDE4_KIO_LIBS}) +target_link_libraries(plasma_wallpaper_mandelbrot \
${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS} ${KDE4_SOLID_LIBS})  
 install(TARGETS plasma_wallpaper_mandelbrot DESTINATION ${PLUGIN_INSTALL_DIR})
 install(FILES plasma-wallpaper-mandelbrot.desktop DESTINATION \
                ${SERVICES_INSTALL_DIR})
--- trunk/playground/base/plasma/wallpapers/mandelbrot/mandelbrot.cpp #949119:949120
@@ -1,4 +1,4 @@
-// Copyright 2008 by Benoît Jacob <jacob.benoit.1@gmail.com>
+// Copyright 2008-2009 by Benoît Jacob <jacob.benoit.1@gmail.com>
 // 
 // This program is free software; you can redistribute it and/or
 // modify it under the terms of the GNU General Public License as
@@ -18,138 +18,19 @@
 
 
 #include "mandelbrot.h"
-#include "render.h"
 #include <iostream>
-#include <cmath>
 #include <QPainter>
 #include <KDebug>
 #include <QGraphicsSceneMouseEvent>
-#include <KDebug>
 #include <Eigen/Core>
 
 K_EXPORT_PLASMA_WALLPAPER(mandelbrot, Mandelbrot)
 
-void Tile::next()
-{
-    int m_square_horiz_dist[8], m_square_vert_dist[8];
-    for(int i = 0; i < 8; i++) {
-      int x = m_renderFirst.x() - int((1./16. + i/8.) * m_mandelbrot->width());
-      m_square_horiz_dist[i] = x*x;
-      int y = m_renderFirst.y() - int((1./16. + i/8.) * m_mandelbrot->height());
-      m_square_vert_dist[i] = y*y;
-    }
-
-    int min_square_distance = INT_MAX;
-    for(int i = 0; i < 8; i++) for(int j = 0; j < 8; j++) {
-        if(m_board[i][j] == 0) {
-            int square_distance = m_square_horiz_dist[i] + m_square_vert_dist[j];
-            if(square_distance<min_square_distance) {
-                m_x = i;
-                m_y = j;
-                min_square_distance = square_distance;
-            }
-        }
-    }
-
-    m_board[m_x][m_y] = 1;
-    m_number++;
-}
-
-void Tile::restart(const QPointF& renderFirst)
-{
-    m_number = 1;
-    m_renderFirst = QPoint((int)renderFirst.x(), (int)renderFirst.y());
-    for(int i = 0; i < 8; i++) for(int j = 0; j < 8; j++) m_board[i][j] = 0;
-    m_x = 8 * renderFirst.x() / m_mandelbrot->width();
-    m_y = 8 * renderFirst.y() / m_mandelbrot->height();
-    if(m_x < 0) m_x = 0;
-    if(m_y < 0) m_y = 0;
-    if(m_x > 7) m_x = 7;
-    if(m_y > 7) m_y = 7;
-    m_board[m_x][m_y] = 1;
-}
-
-bool Tile::final() const
-{
-    return m_number >= 64;
-}
-
-QPointF Tile::affix() const
-{
-    return QPointF(m_mandelbrot->center().x() + (-1+qreal(m_x)/4) * \
                m_mandelbrot->zoom(),
-                   m_mandelbrot->center().y() + (-1+qreal(m_y)/4) * \
                m_mandelbrot->zoom()
-                                                * m_mandelbrot->height() / \
                m_mandelbrot->width());
-}
-
-QRect Tile::destination() const
-{
-    int left = m_x*m_mandelbrot->width()/8;
-    int top = m_y*m_mandelbrot->height()/8;
-    int next_left = (m_x+1)*m_mandelbrot->width()/8;
-    int next_top = (m_y+1)*m_mandelbrot->height()/8;
-    return QRect(left, top, next_left-left, next_top-top);
-}
-
-void MandelbrotRenderThread::run()
-{
-    if(m_id == 0)
-    {
-      int max_iter = 150 * (-std::log(m_mandelbrot->resolution()));
-      max_iter = (max_iter / 4) * 4;
-
-      m_mandelbrot->m_min_iter_divergence = max_iter;
-      m_mandelbrot->m_max_iter_divergence = 0;
-
-      for(int i = 0; i < 100; i++)
-      {
-        qreal x_start = Eigen::ei_random<qreal>(m_mandelbrot->center().x() - \
                m_mandelbrot->zoom(), m_mandelbrot->center().x() + \
                m_mandelbrot->zoom());
-        qreal y_start = Eigen::ei_random<qreal>(m_mandelbrot->center().y() - \
m_mandelbrot->zoom() * m_mandelbrot->height()/m_mandelbrot->width(), \
m_mandelbrot->center().y() + \
                m_mandelbrot->zoom()*m_mandelbrot->height()/m_mandelbrot->width());
-        qreal x = x_start;
-        qreal y = y_start;
-        int iter = 0;
-        bool diverged = false;
-        do {
-          qreal tmp = (x*x - y*y + x_start);
-          y = (2*x*y + y_start);
-          x = tmp;
-          if((x*x + y*y) > 4) diverged = true;
-          else iter++;
-        } while(iter < max_iter && !diverged);
-        if(iter < m_mandelbrot->m_min_iter_divergence) \
                m_mandelbrot->m_min_iter_divergence = iter;
-        if(iter > m_mandelbrot->m_max_iter_divergence) \
                m_mandelbrot->m_max_iter_divergence = iter;
-      }
-    }
-
-run_again:
-    if(m_id < m_mandelbrot->m_renderThreadCount-1)
-        m_mandelbrot->m_renderThreads[m_id+1]->start(QThread::LowPriority);
-      
-    if(m_mandelbrot->resolution() > 1e-7)
-      mandelbrot_render_with_vectorization<float>(m_mandelbrot, m_id);
-    else
-      mandelbrot_render_with_vectorization<double>(m_mandelbrot, m_id);
-
-    if(m_id == 0)
-    {
-        for(int th = 1; th < m_mandelbrot->m_renderThreadCount; th++)
-          m_mandelbrot->m_renderThreads[th]->wait();
-        emit m_mandelbrot->update(m_mandelbrot->m_tile.destination());
-        if(m_mandelbrot->m_abortRenderingAsSoonAsPossible)
-        {
-            return;
-        }
-        if(!m_mandelbrot->m_tile.final())
-        {
-            m_mandelbrot->m_tile.next();
-            goto run_again;
-        }
-    }
-}
-
 Mandelbrot::Mandelbrot(QObject *parent, const QVariantList &args)
     : Plasma::Wallpaper(parent, args), m_color(Qt::gray), m_image(0), m_tile(this),
       m_abortRenderingAsSoonAsPossible(false)
 {
+    m_hasSSE2 = system_has_SSE2();
     m_renderThreadCount = QThread::idealThreadCount();
     m_renderThreads = new MandelbrotRenderThread*[m_renderThreadCount];
     for(int th = 0; th < m_renderThreadCount; th++) m_renderThreads[th] = new \
MandelbrotRenderThread(this, th); @@ -167,6 +48,13 @@
     painter->drawImage(exposedRect, *m_image, exposedRect);
 }
 
+void Mandelbrot::save(KConfigGroup &config)
+{
+    config.writeEntry("mandelbrotcolor", m_color);
+    config.writeEntry("mandelbrotcenter", m_center);
+    config.writeEntry("mandelbrotzoom", m_zoom);
+}
+
 void Mandelbrot::init(const KConfigGroup &config)
 {
     abortRendering();
@@ -205,13 +93,6 @@
     }
 }
 
-void Mandelbrot::save(KConfigGroup &config)
-{
-    config.writeEntry("mandelbrotcolor", m_color);
-    config.writeEntry("mandelbrotcenter", m_center);
-    config.writeEntry("mandelbrotzoom", m_zoom);
-}
-
 void Mandelbrot::mousePressEvent(QGraphicsSceneMouseEvent *event)
 {
     m_mousePressPos = m_mouseLastMovePos = event->pos();
--- trunk/playground/base/plasma/wallpapers/mandelbrot/mandelbrot.h #949119:949120
@@ -1,4 +1,4 @@
-// Copyright 2008 by Benoît Jacob <jacob.benoit.1@gmail.com>
+// Copyright 2008-2009 by Benoît Jacob <jacob.benoit.1@gmail.com>
 // 
 // This program is free software; you can redistribute it and/or
 // modify it under the terms of the GNU General Public License as
@@ -21,47 +21,16 @@
 #define MANDELBROT_HEADER
 
 #include <QColor>
-#include <plasma/wallpaper.h>
-#include <QThread>
 #include <QRect>
+#include <plasma/wallpaper.h>
+#include <KDebug>
 
 #include "ui_config.h"
 
-#define MAX_PACKET_SIZE 4
+#include "global.h"
+#include "tile.h"
+#include "renderthread.h"
 
-class Mandelbrot;
-
-class Tile
-{
-        Mandelbrot * const m_mandelbrot;
-        int m_x, m_y;
-        int m_number;
-        int m_board[8][8];
-        QPoint m_renderFirst;
-
-    public:
-        Tile(Mandelbrot *m, int x=3, int y=3) : m_mandelbrot(m), m_x(x), m_y(y) {}
-        ~Tile() {}
-        QRect destination() const;
-        QPointF affix() const;
-        void next();
-        void restart(const QPointF& renderFirst);
-        bool final() const;
-};
-
-class MandelbrotRenderThread : public QThread
-{
-    friend class Mandelbrot;
-    Mandelbrot * const m_mandelbrot;
-    long long total_iter;
-    int m_id;
-
-  public:
-    MandelbrotRenderThread(Mandelbrot *w, int i) : m_mandelbrot(w), m_id(i) {}
-    ~MandelbrotRenderThread() {}
-    void run();
-};
-
 class Mandelbrot : public Plasma::Wallpaper
 {
     friend class MandelbrotRenderThread;
@@ -86,6 +55,7 @@
         qreal resolution() const { return 2*zoom()/width(); }
         int min_iter_divergence() const { return m_min_iter_divergence; }
         int max_iter_divergence() const { return m_max_iter_divergence; }
+        bool hasSSE2() const { return m_hasSSE2; }
 
     protected:
         virtual void init(const KConfigGroup &config);
@@ -115,6 +85,7 @@
         bool m_abortRenderingAsSoonAsPossible;
         QTime m_timeOfLastMouseMove;
         int m_min_iter_divergence, m_max_iter_divergence;
+        bool m_hasSSE2;
 };
 
 #endif
--- trunk/playground/base/plasma/wallpapers/mandelbrot/render.h #949119:949120
@@ -1,4 +1,4 @@
-// Copyright 2008 by Benoît Jacob <jacob.benoit.1@gmail.com>
+// Copyright 2008-2009 by Benoît Jacob <jacob.benoit.1@gmail.com>
 // 
 // This program is free software; you can redistribute it and/or
 // modify it under the terms of the GNU General Public License as
@@ -19,12 +19,14 @@
 #ifndef RENDER_HEADER
 #define RENDER_HEADER
 
-#define mandelbrot_render mandelbrot_render_without_vectorization
+namespace with_arch_defaults
+{
 #include "render_impl.h"
-#undef mandelbrot_render
+}
 
-#define mandelbrot_render mandelbrot_render_with_vectorization
+namespace with_SSE2_explicitly_enabled_if_x86
+{
 #include "render_impl.h"
-#undef mandelbrot_render
+}
 
 #endif // RENDER_HEADER
--- trunk/playground/base/plasma/wallpapers/mandelbrot/render_impl.cpp #949119:949120
@@ -1,4 +1,4 @@
-// Copyright 2008 by Benoît Jacob <jacob.benoit.1@gmail.com>
+// Copyright 2008-2009 by Benoît Jacob <jacob.benoit.1@gmail.com>
 // 
 // This program is free software; you can redistribute it and/or
 // modify it under the terms of the GNU General Public License as
@@ -19,6 +19,12 @@
 #include <Eigen/Array>
 #include "mandelbrot.h"
 
+#ifdef THIS_IS_PATH_WITH_SSE2_EXPLICTLY_ENABLED
+namespace with_SSE2_explicitly_enabled_if_x86 {
+#else
+namespace with_arch_defaults {
+#endif
+
 template<typename T> struct iter_before_test { enum { ret = 4 }; };
 template<> struct iter_before_test<double> { enum { ret = 4 }; };
 
@@ -27,6 +33,14 @@
   int interleaving_number
 )
 {
+  long long total_iter = 0;
+
+  kDebug() << "SSE2:" << mandelbrot->hasSSE2() << " sizeof " << sizeof(Real);
+
+// if we're compiling the path with SSE2 explicitly enabled, since it's only used on \
x86 (and not even on x86-64 since it has SSE2 by +// default), let's only compile the \
code if it's going to be used! +
+#if defined(WILL_USE_PATH_WITH_SSE2_EXPLICTLY_ENABLED) || \
!defined(THIS_IS_PATH_WITH_SSE2_EXPLICTLY_ENABLED)  enum { packet_size = \
Eigen::ei_packet_traits<Real>::size }; // number of reals in a Packet  typedef \
Eigen::Matrix<Real, packet_size, 1> Packet; // wrap a Packet as a vector  typedef \
Eigen::Matrix<int, packet_size, 1> Packeti; @@ -41,8 +55,6 @@
   int max_iter = 150 * (-std::log(resolution));
   max_iter = (max_iter / iter_before_test) * iter_before_test; // max_iter must be a \
multiple of iter_before_test  
-  long long total_iter = 0;
-
   for(int y = interleaving_number; y < destination.height(); y += \
interleaving_count)  {
     // we must call the const version of scanLine() otherwise it detaches, makes a \
deep copy, and eventually crashes @@ -115,7 +127,7 @@
       }
     }
   }
-
+#endif
   return total_iter;
 }
 
@@ -128,3 +140,5 @@
   Mandelbrot *mandelbrot,
   int interleaving_number
 );
+
+}
\ No newline at end of file
--- trunk/playground/base/plasma/wallpapers/mandelbrot/render_impl.h #949119:949120
@@ -1,4 +1,4 @@
-// Copyright 2008 by Benoît Jacob <jacob.benoit.1@gmail.com>
+// Copyright 2008-2009 by Benoît Jacob <jacob.benoit.1@gmail.com>
 // 
 // This program is free software; you can redistribute it and/or
 // modify it under the terms of the GNU General Public License as
** trunk/playground/base/plasma/wallpapers/mandelbrot/render_with_SSE2_explicitly_enabled_if_x86.cpp \
#property svn:mergeinfo  + 
** trunk/playground/base/plasma/wallpapers/mandelbrot/render_with_arch_defaults.cpp \
#property svn:mergeinfo  + 
** trunk/playground/base/plasma/wallpapers/mandelbrot/renderthread.cpp #property \
svn:mergeinfo  + 
** trunk/playground/base/plasma/wallpapers/mandelbrot/renderthread.h #property \
svn:mergeinfo  + 
** trunk/playground/base/plasma/wallpapers/mandelbrot/tile.cpp #property \
svn:mergeinfo  + 
** trunk/playground/base/plasma/wallpapers/mandelbrot/tile.h #property svn:mergeinfo
   + 


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic