[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