ROOT  6.06/09
Reference Guide
mandel.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010-2011 Matthias Kretz <kretz@kde.org>
3 
4  Permission to use, copy, modify, and distribute this software
5  and its documentation for any purpose and without fee is hereby
6  granted, provided that the above copyright notice appear in all
7  copies and that both that the copyright notice and this
8  permission notice and warranty disclaimer appear in supporting
9  documentation, and that the name of the author not be used in
10  advertising or publicity pertaining to distribution of the
11  software without specific, written prior permission.
12 
13  The author disclaim all warranties with regard to this
14  software, including all implied warranties of merchantability
15  and fitness. In no event shall the author be liable for any
16  special, indirect or consequential damages or any damages
17  whatsoever resulting from loss of use, data or profits, whether
18  in an action of contract, negligence or other tortious action,
19  arising out of or in connection with the use or performance of
20  this software.
21 
22 */
23 
24 #include "mandel.h"
25 #include <QMutexLocker>
26 #include <QtCore/QtDebug>
27 #include "../tsc.h"
28 
29 #include <Vc/vector.h>
30 #include <Vc/common/macros.h>
31 
32 using Vc::float_v;
33 using Vc::float_m;
34 using Vc::uint_v;
35 using Vc::uint_m;
36 
37 template<MandelImpl Impl>
38 Mandel<Impl>::Mandel(QObject *_parent)
39  : MandelBase(_parent)
40 {
41 }
42 
43 MandelBase::MandelBase(QObject *_parent)
44  : QThread(_parent),
45  m_restart(false), m_abort(false)
46 {
47 }
48 
50 {
51  m_mutex.lock();
52  m_abort = true;
53  m_wait.wakeOne();
54  m_mutex.unlock();
55 
56  wait();
57 }
58 
59 void MandelBase::brot(const QSize &size, float x, float y, float scale)
60 {
61  QMutexLocker lock(&m_mutex);
62 
63  m_size = size;
64  m_x = x;
65  m_y = y;
66  m_scale = scale;
67 
68  if (!isRunning()) {
69  start(LowPriority);
70  } else {
71  m_restart = true;
72  m_wait.wakeOne();
73  }
74 }
75 
77 {
78  while (!m_abort) {
79  // first we copy the parameters to our local data so that the main main thread can give a
80  // new task while we're working
81  m_mutex.lock();
82  // destination image, RGB is good - no need for alpha
83  QImage image(m_size, QImage::Format_RGB32);
84  float x = m_x;
85  float y = m_y;
86  float scale = m_scale;
87  m_mutex.unlock();
88 
89  // benchmark the number of cycles it takes
91  timer.Start();
92 
93  // calculate the mandelbrot set/image
94  mandelMe(image, x, y, scale, 255);
95 
96  timer.Stop();
97 
98  // if no new set was requested in the meantime - return the finished image
99  if (!m_restart) {
100  emit ready(image, timer.Cycles());
101  }
102 
103  // wait for more work
104  m_mutex.lock();
105  if (!m_restart) {
106  m_wait.wait(&m_mutex);
107  }
108  m_restart = false;
109  m_mutex.unlock();
110  }
111 }
112 
113 static const float S = 4.f;
114 
115 /**
116  * std::complex is way too slow for our limited purposes:
117  *
118  * norm is implemented as std::abs(z) * std::abs(z) for float
119  * z * z is implemented as multiplication & lots of branches looking for NaN and inf
120  *
121  * since we know that we require the square of r and i for norm and multiplication we can
122  * explicitely cache it in the object
123  */
124 //! [MyComplex]
125 template<typename T>
126 class MyComplex
127 {
128  public:
129  MyComplex(T r, T i)
130  : m_real(r), m_imag(i),
131  m_real2(r * r), m_imag2(i * i)
132  {
133  }
134 
135  MyComplex squaredPlus(T r, T i) const
136  {
137  return MyComplex(
138  m_real2 + r - m_imag2,
139  (m_real + m_real) * m_imag + i
140  );
141  }
142 
143  T norm() const
144  {
145  return m_real2 + m_imag2;
146  }
147 
148  private:
149  T m_real, m_imag;
150  T m_real2, m_imag2;
151 };
152 //! [MyComplex]
153 
154 //! [P function]
155 template<typename T> inline MyComplex<T> P(MyComplex<T> z, T c_real, T c_imag)
156 {
157  return z.squaredPlus(c_real, c_imag);
158 }
159 //! [P function]
160 
161 template<> void Mandel<VcImpl>::mandelMe(QImage &image, float x0,
162  float y0, float scale, int maxIt)
163 {
164  typedef MyComplex<float_v> Z;
165  const unsigned int height = image.height();
166  const unsigned int width = image.width();
167  const float_v colorScale = 0xff / static_cast<float>(maxIt);
168  for (unsigned int y = 0; y < height; ++y) {
169  unsigned int *VC_RESTRICT line = reinterpret_cast<unsigned int *>(image.scanLine(y));
170  const float_v c_imag = y0 + y * scale;
171  uint_m toStore;
172  for (uint_v x = uint_v::IndexesFromZero(); !(toStore = x < width).isEmpty();
173  x += float_v::Size) {
174  const float_v c_real = x0 + x * scale;
175  Z z(c_real, c_imag);
176  float_v n = 0.f;
177  float_m inside = z.norm() < S;
178  while (!(inside && n < maxIt).isEmpty()) {
179  z = P(z, c_real, c_imag);
180  ++n(inside);
181  inside = z.norm() < S;
182  }
183  uint_v colorValue = static_cast<uint_v>((maxIt - n) * colorScale) * 0x10101;
184  if (toStore.isFull()) {
185  colorValue.store(line, Vc::Unaligned);
186  line += uint_v::Size;
187  } else {
188  colorValue.store(line, toStore, Vc::Unaligned);
189  break; // we don't need to check again wether x[0] + float_v::Size < width to break out of the loop
190  }
191  }
192  if (restart()) {
193  break;
194  }
195  }
196 }
197 
198 template<> void Mandel<ScalarImpl>::mandelMe(QImage &image, float x0,
199  float y0, float scale, int maxIt)
200 {
201  typedef MyComplex<float> Z;
202  const int height = image.height();
203  const int width = image.width();
204  const float colorScale = 0xff / static_cast<float>(maxIt);
205  for (int y = 0; y < height; ++y) {
206  unsigned int *VC_RESTRICT line = reinterpret_cast<unsigned int *>(image.scanLine(y));
207  const float c_imag = y0 + y * scale;
208  for (int x = 0; x < width; ++x) {
209  const float c_real = x0 + x * scale;
210  Z z(c_real, c_imag);
211  int n = 0;
212  for (; z.norm() < S && n < maxIt; ++n) {
213  z = P(z, c_real, c_imag);
214  }
215  *line++ = static_cast<unsigned int>((maxIt - n) * colorScale) * 0x10101;
216  }
217  if (restart()) {
218  break;
219  }
220  }
221 }
222 
223 template class Mandel<VcImpl>;
224 template class Mandel<ScalarImpl>;
225 
226 // vim: sw=4 sts=4 et tw=100
void run()
Definition: mandel.cpp:76
TLine * line
~MandelBase()
Definition: mandel.cpp:49
const char * Size
Definition: TXMLSetup.cxx:56
double T(double x)
Definition: ChebyshevPol.h:34
void Stop()
Definition: tsc.h:53
QSize m_size
Definition: mandel.h:56
ClassImp(TIterator) Bool_t TIterator return false
Compare two iterator objects.
Definition: TIterator.cxx:20
bool m_restart
Definition: mandel.h:58
float m_x
Definition: mandel.h:57
virtual void mandelMe(QImage &image, float x, float y, float scale, int maxIterations)=0
TStopwatch timer
Definition: pirndm.C:37
Double_t x[n]
Definition: legend1.C:17
float_v::Mask float_m
Definition: vector.h:424
unsigned long long Cycles() const
Definition: tsc.h:63
QMutex m_mutex
Definition: mandel.h:54
float m_scale
Definition: mandel.h:57
ROOT::R::TRInterface & r
Definition: Object.C:4
uint_v::Mask uint_m
Definition: vector.h:427
QWaitCondition m_wait
Definition: mandel.h:55
MandelBase(QObject *_parent=0)
Definition: mandel.cpp:43
MyComplex< T > P(MyComplex< T > z, T c_real, T c_imag)
[MyComplex]
Definition: mandel.cpp:155
Vector< unsigned int > uint_v
Definition: vector.h:420
static const float S
Definition: mandel.cpp:113
float m_y
Definition: mandel.h:57
Double_t y[n]
Definition: legend1.C:17
bool restart() const
Definition: mandel.h:48
#define VC_RESTRICT
Definition: macros.h:145
bool m_abort
Definition: mandel.h:59
void brot(const QSize &size, float x, float y, float scale)
Definition: mandel.cpp:59
std::complex< float_v > Z
Definition: main.cpp:120
void Start()
Definition: tsc.h:43
double norm(double *x, double *p)
Definition: unuranDistr.cxx:40
const Int_t n
Definition: legend1.C:16
Mandel(QObject *_parent=0)
Definition: mandel.cpp:38
void ready(const QImage &image, quint64 cycles)
void mandelMe(QImage &image, float x, float y, float scale, int maxIterations)
const char Int_t const char * image
Definition: TXSlave.cxx:46
Vector< float > float_v
Definition: vector.h:417