![]() |
Mali OpenCL SDK v1.1.0
|
The results of calculating the Mandelbrot set produces fractal patterns.
A complex number is in the Mandelbrot set if the it doesn't tend to infinity when a given equation is iterated on the number.
The equation used is:
zn+1 = zn2 + c
where c is the complex number and n is the iteration. z0 is set as 0.
To produce a visualization of the set, like the one shown above, you can treat the x and y pixel coordinates of an image as the real and imaginary components of a complex number. For example, at (2, 1) the complex number c = 2 + 1i.
It can be shown that if the distance from zn to the origin is greater than 2 for any value of n, it is unbounded and therefore not part of the Mandelbrot set.
Examples:
Not in the Mandelbrot set:
c = 2 + 1i
z0 = 0
z1 = 2 + 1i
If you use 2 + 1i as coordinates (2, 1) then the euquidean distance to the origin is sqrt(22 + 12) = 2.24.
2.24 > 2 and therefore for this input the equation is unbounded and the input is not part of the Mandelbrot set.
In the Mandelbrot set:
c = 0 + 1i
z0 = 0
z1 = 0 + 1i
z2 = -1 + 1i
z3 = 0 - 1i
z4 = -1 + 1i
You can see that this is forming a repeating pattern that will never become unbounded.
To create the output image, the number of iterations taken to determine whether the point is or is not part of the Mandelbrot set is used as the pixel intensity. A limit is placed on the number of iterations such that cases like c = 0 + 1i do not run forever. Therefore, a pixel which is in the Mandelbrot set will have a value equal to the maximum number of iterations.
For more details see Wikipedia.
Unless otherwise noted, all code snippets come from the OpenCL kernel found in mandelbrot.cl.
Choosing the size of the kernel
We are using vector types in the kernel and so we are actually outputting 4 results per kernel. See below for more details of vectorising. We split the data for the real and imaginary parts in order to be able to represent it.
We adjust the pointers into the data to reflect this:
And when we enqueue the kernel in mandelbrot.cpp, we reduce the worksize accordingly:
Creating the inputs
Mali-T600 series GPU pipelines provide true IEEE-754 single-precision floating-point math in hardware. Each Mali-T600 series GPU core has a minimum of two 128-bit wide ALUs (Arithmetic logic units). Each ALU can do a maximum of two vector floating point operations per cycle (one vector floating point addition and one vector floating point multiplication).
In this sample, the calculations use 32-bit floating point numbers. One 128-bit vector can fit four 32-bit floating point numbers. Therefore, using float4's makes maximum use of the hardware.
We recommend the use of vectors wherever possible when using a Mali-T600 series GPU.
Here we create the input vectors:
Doing the calculation
All of the main calculations are done on vectors of 4 floating point numbers. Each vector calculation can be done as a single operation on Mali-T600 series GPU.
The main calculation loop:
Storing the results
Finally we convert the data to unsigned chars and store the data.
Pixels in the Mandelbrot set will have the value of MAX_ITER.
We use a vector store to write out all 4 results at once:
From a command prompt in the root of the SDK, run:
From a command prompt in the root of the SDK, run:
This compiles the Mandelbrot sample code and copies all the files it needs to run to the bin folder in the root directory of the SDK.
Navigate to the folder on the board and run the Mandelbrot binary:
You should see output similar to:
An output image should be created on the board called output.bmp.
Find solutions for Common Issues.
For more information have a look at the code in mandelbrot.cpp and mandelbrot.cl.