Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F121712286
mandelbrot.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Jul 13, 09:16
Size
7 KB
Mime Type
text/x-c
Expires
Tue, Jul 15, 09:16 (2 d)
Engine
blob
Format
Raw Data
Handle
27378502
Attached To
rDLMA Diffusion limited mixed aggregation
mandelbrot.cpp
View Options
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "mandelbrot.h"
#include <iostream>
#include<QtGui/QPainter>
#include<QtGui/QImage>
#include<QtGui/QMouseEvent>
#include<QtCore/QTime>
void
MandelbrotWidget
::
resizeEvent
(
QResizeEvent
*
)
{
if
(
size
<
width
()
*
height
())
{
std
::
cout
<<
"reallocate buffer"
<<
std
::
endl
;
size
=
width
()
*
height
();
if
(
buffer
)
delete
[]
buffer
;
buffer
=
new
unsigned
char
[
4
*
size
];
}
}
template
<
typename
T
>
struct
iters_before_test
{
enum
{
ret
=
8
};
};
template
<>
struct
iters_before_test
<
double
>
{
enum
{
ret
=
16
};
};
template
<
typename
Real
>
void
MandelbrotThread
::
render
(
int
img_width
,
int
img_height
)
{
enum
{
packetSize
=
Eigen
::
internal
::
packet_traits
<
Real
>::
size
};
// number of reals in a Packet
typedef
Eigen
::
Array
<
Real
,
packetSize
,
1
>
Packet
;
// wrap a Packet as a vector
enum
{
iters_before_test
=
iters_before_test
<
Real
>::
ret
};
max_iter
=
(
max_iter
/
iters_before_test
)
*
iters_before_test
;
const
int
alignedWidth
=
(
img_width
/
packetSize
)
*
packetSize
;
unsigned
char
*
const
buffer
=
widget
->
buffer
;
const
double
xradius
=
widget
->
xradius
;
const
double
yradius
=
xradius
*
img_height
/
img_width
;
const
int
threadcount
=
widget
->
threadcount
;
typedef
Eigen
::
Array
<
Real
,
2
,
1
>
Vector2
;
Vector2
start
(
widget
->
center
.
x
()
-
widget
->
xradius
,
widget
->
center
.
y
()
-
yradius
);
Vector2
step
(
2
*
widget
->
xradius
/
img_width
,
2
*
yradius
/
img_height
);
total_iter
=
0
;
for
(
int
y
=
id
;
y
<
img_height
;
y
+=
threadcount
)
{
int
pix
=
y
*
img_width
;
// for each pixel, we're going to do the iteration z := z^2 + c where z and c are complex numbers,
// starting with z = c = complex coord of the pixel. pzi and pzr denote the real and imaginary parts of z.
// pci and pcr denote the real and imaginary parts of c.
Packet
pzi_start
,
pci_start
;
for
(
int
i
=
0
;
i
<
packetSize
;
i
++
)
pzi_start
[
i
]
=
pci_start
[
i
]
=
start
.
y
()
+
y
*
step
.
y
();
for
(
int
x
=
0
;
x
<
alignedWidth
;
x
+=
packetSize
,
pix
+=
packetSize
)
{
Packet
pcr
,
pci
=
pci_start
,
pzr
,
pzi
=
pzi_start
,
pzr_buf
;
for
(
int
i
=
0
;
i
<
packetSize
;
i
++
)
pzr
[
i
]
=
pcr
[
i
]
=
start
.
x
()
+
(
x
+
i
)
*
step
.
x
();
// do the iterations. Every iters_before_test iterations we check for divergence,
// in which case we can stop iterating.
int
j
=
0
;
typedef
Eigen
::
Matrix
<
int
,
packetSize
,
1
>
Packeti
;
Packeti
pix_iter
=
Packeti
::
Zero
(),
// number of iteration per pixel in the packet
pix_dont_diverge
;
// whether or not each pixel has already diverged
do
{
for
(
int
i
=
0
;
i
<
iters_before_test
/
4
;
i
++
)
// peel the inner loop by 4
{
# define ITERATE \
pzr_buf = pzr; \
pzr = pzr.square(); \
pzr -= pzi.square(); \
pzr += pcr; \
pzi = (2*pzr_buf)*pzi; \
pzi += pci;
ITERATE
ITERATE
ITERATE
ITERATE
}
pix_dont_diverge
=
((
pzr
.
square
()
+
pzi
.
square
())
.
eval
()
// temporary fix as what follows is not yet vectorized by Eigen
<=
Packet
::
Constant
(
4
))
// the 4 here is not a magic value, it's a math fact that if
// the square modulus is >4 then divergence is inevitable.
.
template
cast
<
int
>
();
pix_iter
+=
iters_before_test
*
pix_dont_diverge
;
j
++
;
total_iter
+=
iters_before_test
*
packetSize
;
}
while
(
j
<
max_iter
/
iters_before_test
&&
pix_dont_diverge
.
any
());
// any() is not yet vectorized by Eigen
// compute pixel colors
for
(
int
i
=
0
;
i
<
packetSize
;
i
++
)
{
buffer
[
4
*
(
pix
+
i
)]
=
255
*
pix_iter
[
i
]
/
max_iter
;
buffer
[
4
*
(
pix
+
i
)
+
1
]
=
0
;
buffer
[
4
*
(
pix
+
i
)
+
2
]
=
0
;
}
}
// if the width is not a multiple of packetSize, fill the remainder in black
for
(
int
x
=
alignedWidth
;
x
<
img_width
;
x
++
,
pix
++
)
buffer
[
4
*
pix
]
=
buffer
[
4
*
pix
+
1
]
=
buffer
[
4
*
pix
+
2
]
=
0
;
}
return
;
}
void
MandelbrotThread
::
run
()
{
setTerminationEnabled
(
true
);
double
resolution
=
widget
->
xradius
*
2
/
widget
->
width
();
max_iter
=
128
;
if
(
resolution
<
1e-4
f
)
max_iter
+=
128
*
(
-
4
-
std
::
log10
(
resolution
));
int
img_width
=
widget
->
width
()
/
widget
->
draft
;
int
img_height
=
widget
->
height
()
/
widget
->
draft
;
single_precision
=
resolution
>
1e-7
f
;
if
(
single_precision
)
render
<
float
>
(
img_width
,
img_height
);
else
render
<
double
>
(
img_width
,
img_height
);
}
void
MandelbrotWidget
::
paintEvent
(
QPaintEvent
*
)
{
static
float
max_speed
=
0
;
long
long
total_iter
=
0
;
QTime
time
;
time
.
start
();
for
(
int
th
=
0
;
th
<
threadcount
;
th
++
)
threads
[
th
]
->
start
(
QThread
::
LowPriority
);
for
(
int
th
=
0
;
th
<
threadcount
;
th
++
)
{
threads
[
th
]
->
wait
();
total_iter
+=
threads
[
th
]
->
total_iter
;
}
int
elapsed
=
time
.
elapsed
();
if
(
draft
==
1
)
{
float
speed
=
elapsed
?
float
(
total_iter
)
*
1000
/
elapsed
:
0
;
max_speed
=
std
::
max
(
max_speed
,
speed
);
std
::
cout
<<
threadcount
<<
" threads, "
<<
elapsed
<<
" ms, "
<<
speed
<<
" iters/s (max "
<<
max_speed
<<
")"
<<
std
::
endl
;
int
packetSize
=
threads
[
0
]
->
single_precision
?
int
(
Eigen
::
internal
::
packet_traits
<
float
>::
size
)
:
int
(
Eigen
::
internal
::
packet_traits
<
double
>::
size
);
setWindowTitle
(
QString
(
"resolution "
)
+
QString
::
number
(
xradius
*
2
/
width
(),
'e'
,
2
)
+
QString
(
", %1 iterations per pixel, "
).
arg
(
threads
[
0
]
->
max_iter
)
+
(
threads
[
0
]
->
single_precision
?
QString
(
"single "
)
:
QString
(
"double "
))
+
QString
(
"precision, "
)
+
(
packetSize
==
1
?
QString
(
"no vectorization"
)
:
QString
(
"vectorized (%1 per packet)"
).
arg
(
packetSize
)));
}
QImage
image
(
buffer
,
width
()
/
draft
,
height
()
/
draft
,
QImage
::
Format_RGB32
);
QPainter
painter
(
this
);
painter
.
drawImage
(
QPoint
(
0
,
0
),
image
.
scaled
(
width
(),
height
()));
if
(
draft
>
1
)
{
draft
/=
2
;
setWindowTitle
(
QString
(
"recomputing at 1/%1 resolution..."
).
arg
(
draft
));
update
();
}
}
void
MandelbrotWidget
::
mousePressEvent
(
QMouseEvent
*
event
)
{
if
(
event
->
buttons
()
&
Qt
::
LeftButton
)
{
lastpos
=
event
->
pos
();
double
yradius
=
xradius
*
height
()
/
width
();
center
=
Eigen
::
Vector2d
(
center
.
x
()
+
(
event
->
pos
().
x
()
-
width
()
/
2
)
*
xradius
*
2
/
width
(),
center
.
y
()
+
(
event
->
pos
().
y
()
-
height
()
/
2
)
*
yradius
*
2
/
height
());
draft
=
16
;
for
(
int
th
=
0
;
th
<
threadcount
;
th
++
)
threads
[
th
]
->
terminate
();
update
();
}
}
void
MandelbrotWidget
::
mouseMoveEvent
(
QMouseEvent
*
event
)
{
QPoint
delta
=
event
->
pos
()
-
lastpos
;
lastpos
=
event
->
pos
();
if
(
event
->
buttons
()
&
Qt
::
LeftButton
)
{
double
t
=
1
+
5
*
double
(
delta
.
y
())
/
height
();
if
(
t
<
0.5
)
t
=
0.5
;
if
(
t
>
2
)
t
=
2
;
xradius
*=
t
;
draft
=
16
;
for
(
int
th
=
0
;
th
<
threadcount
;
th
++
)
threads
[
th
]
->
terminate
();
update
();
}
}
int
main
(
int
argc
,
char
*
argv
[])
{
QApplication
app
(
argc
,
argv
);
MandelbrotWidget
w
;
w
.
show
();
return
app
.
exec
();
}
#include "mandelbrot.moc"
Event Timeline
Log In to Comment