diff --git a/test/tutorial/tut03.cpp b/test/tutorial/tut03.cpp index df6f20e8..259cf3ca 100644 --- a/test/tutorial/tut03.cpp +++ b/test/tutorial/tut03.cpp @@ -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;