2 Copyright (c) 2005-2019 Intel Corporation
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
19 #include "tbb/parallel_for.h"
20 #include "tbb/blocked_range2d.h"
21 #include "tbb/tick_count.h"
28 extern bool schedule_auto;
29 extern int grain_size;
31 color_t fractal::calc_one_pixel( int x0, int y0 ) const {
33 double fx0, fy0, xtemp, x, y, mu;
37 fx0 = (double)x0 - (double) size_x / 2.0;
38 fy0 = (double)y0 - (double) size_y / 2.0;
39 fx0 = fx0 / magn + cx;
40 fy0 = fy0 / magn + cy;
42 iter = 0; x = 0; y = 0;
45 while (((x*x + y*y) <= 4) && (iter < max_iterations)) {
46 xtemp = x*x - y*y + fx0;
49 mu += exp(-sqrt(x*x+y*y));
53 if (iter == max_iterations) {
54 // point corresponds to the mandelbrot set
55 color = v->get_color(255, 255, 255);
59 int b = (int)(256*mu);
67 color = v->get_color(r, g, b);
71 void fractal::clear() {
72 drawing_area area( off_x, off_y, size_x, size_y, dm ) ;
74 // fill the rendering area with black color
75 for (int y=0; y<size_y; ++y) {
77 for (int x=0; x<size_x; ++x) {
78 area.put_pixel( v->get_color(0, 0, 0) );
83 void fractal::draw_border( bool is_active ) {
84 color_t color = is_active ? v->get_color(0, 255, 0) // green color
85 : v->get_color(96, 128, 96); // green-gray color
88 drawing_area area0( off_x-1, off_y-1, size_x+2, 1, dm );
89 for (int i=-1; i<size_x+1; ++i)
90 area0.put_pixel(color);
92 drawing_area area1( off_x-1, off_y+size_y, size_x+2, 1, dm );
93 for (int i=-1; i<size_x+1; ++i)
94 area1.put_pixel(color);
96 drawing_area area2( off_x-1, off_y, 1, size_y+2, dm );
97 for (int i=0; i<size_y; ++i)
98 area2.set_pixel(0, i, color);
100 drawing_area area3( size_x+off_x, off_y, 1, size_y+2, dm );
101 for (int i=0; i<size_y; ++i)
102 area3.set_pixel(0, i, color);
105 void fractal::render_rect( int x0, int y0, int x1, int y1 ) const {
106 // render the specified rectangle area
107 drawing_area area(off_x+x0, off_y+y0, x1-x0, y1-y0, dm);
108 for ( int y=y0; y<y1; ++y ) {
109 area.set_pos( 0, y-y0 );
110 for ( int x=x0; x<x1; ++x ) {
111 area.put_pixel( calc_one_pixel( x, y ) );
119 void operator()( tbb::blocked_range2d<int> &r ) const {
120 if ( v->next_frame() )
121 f.render_rect( r.cols().begin(), r.rows().begin(), r.cols().end(), r.rows().end() );
124 fractal_body( fractal &_f ) : f(_f) {
128 void fractal::render( tbb::task_group_context &context ) {
129 // Make copy of fractal object and render fractal with parallel_for with
130 // the provided context and partitioner chosen by schedule_auto.
131 // Updates to fractal are not reflected in the render.
133 fractal_body body(f);
136 tbb::parallel_for( tbb::blocked_range2d<int>(0, size_y, grain_size, 0, size_x, grain_size ),
137 body, tbb::auto_partitioner(), context);
139 tbb::parallel_for( tbb::blocked_range2d<int>(0, size_y, grain_size, 0, size_x, grain_size ),
140 body, tbb::simple_partitioner(), context);
143 void fractal::run( tbb::task_group_context &context ) {
149 bool fractal::check_point( int x, int y ) const {
150 return x >= off_x && x <= off_x+size_x &&
151 y >= off_y && y <= off_y+size_y;
154 void fractal_group::calc_fractal( int num ) {
155 // calculate the fractal
156 fractal &f = num ? f1 : f0;
158 tbb::tick_count t0 = tbb::tick_count::now();
159 while ( v->next_frame() && num_frames[num] != 0 ) {
160 f.run( context[num] );
161 if ( num_frames[num]>0 ) num_frames[num] -= 1;
163 tbb::tick_count t1 = tbb::tick_count::now();
166 printf(" %s fractal finished. Time: %g\n", num ? "Second" : "First", (t1-t0).seconds());
170 void fractal_group::switch_active( int new_active ) {
171 if( new_active!=-1 ) active = new_active;
172 else active = 1-active; // assumes 'active' is only 0 or 1
176 void fractal_group::set_num_frames_at_least( int n ) {
177 if ( num_frames[0]<n ) num_frames[0] = n;
178 if ( num_frames[1]<n ) num_frames[1] = n;
181 void fractal_group::run( bool create_second_fractal ) {
182 // First argument of arenas construntor is used to restrict concurrency
183 arenas[0].initialize(num_threads);
184 arenas[1].initialize(num_threads / 2);
188 // the second fractal is calculating on separated thread
189 if ( create_second_fractal ) {
190 arenas[1].execute( [&] {
191 groups[1].run( [&] { calc_fractal( 1 ); } );
195 arenas[0].execute( [&] {
196 groups[0].run( [&] { calc_fractal( 0 ); } );
199 if ( create_second_fractal ) {
200 arenas[1].execute( [&] { groups[1].wait(); } );
203 arenas[0].execute( [&] { groups[0].wait(); } );
206 void fractal_group::draw_borders() {
207 f0.draw_border( active==0 );
208 f1.draw_border( active==1 );
211 fractal_group::fractal_group( const drawing_memory &_dm, int _num_threads, unsigned int _max_iterations, int _num_frames ) : f0(_dm), f1(_dm), num_threads(_num_threads) {
212 // set rendering areas
213 f0.size_x = f1.size_x = _dm.sizex/2-4;
214 f0.size_y = f1.size_y = _dm.sizey-4;
215 f0.off_x = f0.off_y = f1.off_y = 2;
216 f1.off_x = f0.size_x+4+2;
218 // set fractals parameters
219 f0.cx = -0.6f; f0.cy = 0.0f; f0.magn = 200.0f;
220 f1.cx = -0.6f; f1.cy = 0.0f; f1.magn = 200.0f;
221 f0.max_iterations = f1.max_iterations = _max_iterations;
223 // initially the first fractal is active
226 num_frames[0] = num_frames[1] = _num_frames;
229 void fractal_group::mouse_click( int x, int y ) {
230 // assumption that the point is not inside any fractal area
233 if ( f0.check_point( x, y ) ) {
234 // the point is inside the first fractal area
236 } else if ( f1.check_point( x, y ) ) {
237 // the point is inside the second fractal area
241 if ( new_active != -1 && new_active != active ) {
242 switch_active( new_active );