Browse Source

test: proper multithreading in the Mandelbrot tutorial.

legacy
Sam Hocevar sam 13 years ago
parent
commit
608f52eefb
1 changed files with 42 additions and 33 deletions
  1. +42
    -33
      test/tutorial/tut03.cpp

+ 42
- 33
test/tutorial/tut03.cpp View File

@@ -104,9 +104,9 @@ public:
{
double f = (double)i / PALETTE_STEP;

double r = 0.5 * sin(f * 0.27 - 2.5) + 0.5;
double g = 0.5 * sin(f * 0.13 + 1.1) + 0.5;
double b = 0.5 * sin(f * 0.21 + 0.4) + 0.5;
double r = 0.5 * sin(f * 0.27 + 2.0) + 0.5;
double g = 0.5 * sin(f * 0.17 - 1.8) + 0.5;
double b = 0.5 * sin(f * 0.21 - 2.6) + 0.5;

if (f < 7.0)
{
@@ -146,10 +146,20 @@ public:
bbox[0] = position;
bbox[1] = ivec3(m_window_size, 0);
Input::TrackMouse(this);

/* Spawn worker threads and wait for their readiness. */
for (int i = 0; i < MAX_THREADS; i++)
m_threads[i] = new Thread(DoWorkHelper, this);
for (int i = 0; i < MAX_THREADS; i++)
m_spawnqueue.Pop();
}

~Fractal()
{
/* Signal worker threads for completion. */
for (int i = 0; i < MAX_THREADS; i++)
m_jobqueue.Push(-1);

Input::UntrackMouse(this);
#if !defined __native_client__
Ticker::Unref(m_centertext);
@@ -307,49 +317,39 @@ public:
{
m_dirty[m_frame]--;

/* FIXME: this is the ugliest, most pathetic excuse for a
* threading system that I have seen in a while. */
DoWorkHelper helpers[m_slices];
for (int slice = 0; slice < m_slices; slice++)
{
helpers[slice].fractal = this;
helpers[slice].slice = slice;
// helpers[slice].thread = new Thread(DoWorkHelper::Help,
// &helpers[slice]);
DoWork(slice);
}
for (int slice = 0; slice < m_slices; slice++)
{
// delete helpers[slice].thread;
}
for (int i = 0; i < m_size.y; i += MAX_LINES * 2)
m_jobqueue.Push(i);
}
}

struct DoWorkHelper
static void *DoWorkHelper(void *data)
{
Fractal *fractal;
Thread *thread;
int slice;

static void *Help(void *data)
Fractal *that = (Fractal *)data;
that->m_spawnqueue.Push(0);
for ( ; ; )
{
DoWorkHelper *helper = (DoWorkHelper *)data;
helper->fractal->DoWork(helper->slice);
return NULL;
int line = that->m_jobqueue.Pop();
if (line == -1)
break;
that->DoWork(line);
that->m_donequeue.Push(0);
}
return NULL;
};

void DoWork(int slice)
void DoWork(int line)
{
double const maxsqlen = 1024;
double const k1 = 1.0 / (1 << 10) / log2(maxsqlen);

int jmin = m_size.y * slice / m_slices;
int jmax = m_size.y * (slice + 1) / m_slices;
int jmin = ((m_frame + 1) % 4) / 2 + line;
int jmax = jmin + MAX_LINES * 2;
if (jmax > m_size.y)
jmax = m_size.y;
u8vec4 *m_pixelstart = m_pixels
+ m_size.x * (m_size.y / 4 * m_frame + jmin / 4);
+ m_size.x * (m_size.y / 4 * m_frame + line / 4);

for (int j = ((m_frame + 1) % 4) / 2 + jmin; j < jmax; j += 2)
for (int j = jmin; j < jmax; j += 2)
for (int i = m_frame % 2; i < m_size.x; i += 2)
{
f64cmplx z0 = m_center + TexelToWorldOffset(ivec2(i, j));
@@ -659,6 +659,9 @@ DoWork(slice);

if (m_dirty[m_frame])
{
for (int i = 0; i < m_size.y; i += MAX_LINES * 2)
m_donequeue.Pop();

m_dirty[m_frame]--;

#ifdef __CELLOS_LV2__
@@ -718,8 +721,10 @@ DoWork(slice);
}

private:
static int const MAX_ITERATIONS = 170;
static int const MAX_ITERATIONS = 340;
static int const PALETTE_STEP = 32;
static int const MAX_THREADS = 8;
static int const MAX_LINES = 8;

ivec2 m_size, m_window_size, m_oldmouse;
double m_window2world;
@@ -745,6 +750,10 @@ private:
f64cmplx m_deltashift[4];
double m_deltascale[4];

/* Worker threads */
Thread *m_threads[MAX_THREADS];
Queue m_spawnqueue, m_jobqueue, m_donequeue;

/* Debug information */
#if !defined __native_client__
Text *m_centertext, *m_mousetext, *m_zoomtext;


Loading…
Cancel
Save