diff --git a/src/apps/mandelbrot/FractalEngine.cpp b/src/apps/mandelbrot/FractalEngine.cpp index daea40614f..c20b2511df 100644 --- a/src/apps/mandelbrot/FractalEngine.cpp +++ b/src/apps/mandelbrot/FractalEngine.cpp @@ -33,13 +33,13 @@ FractalEngine::FractalEngine(BHandler* parent, BLooper* looper) fRenderBuffer(NULL), fRenderBufferLen(0), fMessenger(parent, looper), - fThreadsRendering(0), fIterations(1024), fColorset(Colorset_Royal) { fDoSet = &FractalEngine::DoSet_Mandelbrot; fRenderSem = create_sem(0, "RenderSem"); + fRenderStoppedSem = create_sem(0,"RenderStopped"); system_info info; get_system_info(&info); @@ -49,8 +49,6 @@ FractalEngine::FractalEngine(BHandler* parent, BLooper* looper) fThreadCount = MAX_RENDER_THREADS; for (uint8 i = 0; i < fThreadCount; i++) { - fRestartRenderThread[i] = false; - fRenderThreadRunning[i] = false; fRenderThreads[i] = spawn_thread(&FractalEngine::RenderThread, BString().SetToFormat("RenderThread%d", i).String(), B_NORMAL_PRIORITY, this); @@ -95,6 +93,14 @@ void FractalEngine::MessageReceived(BMessage* msg) break; case MSG_RESIZE: { + TRACE("Got MSG_RESIZE threads rendering\n"); + if (fStopRender) { + // Will be true throughout this whole handler. Set false at the end + TRACE("Breaking out of MSG_RESIZE handler\n"); + break; + } + StopRender(); + delete fRenderBuffer; fRenderBuffer = NULL; @@ -102,17 +108,20 @@ void FractalEngine::MessageReceived(BMessage* msg) fHeight = msg->GetUInt16("height", 240); TRACE("Creating new buffer. width %u height %u\n", fWidth, fHeight); - fRenderBufferLen = fWidth * fHeight * 3; fRenderBuffer = new uint8[fRenderBufferLen]; memset(fRenderBuffer, 0, fRenderBufferLen); BMessage message(MSG_BUFFER_CREATED); fMessenger.SendMessage(&message); + + fStopRender = false; break; } case MSG_RENDER: { - TRACE("Got MSG_RENDER. fThreadsRendering = %u\n",fThreadsRendering); + TRACE("Got MSG_RENDER.\n"); + StopRender(); + fStopRender = false; Render(msg->GetDouble("locationX", 0), msg->GetDouble("locationY", 0), msg->GetDouble("size", 0.005)); break; @@ -121,9 +130,9 @@ void FractalEngine::MessageReceived(BMessage* msg) TRACE("Got MSG_THREAD_RENDER_COMPLETE for thread %d\n", msg->GetUInt8("thread", 0)); - fThreadsRendering--; - TRACE("Set fRendering = %d\n", fThreadsRendering); - if (!fThreadsRendering) { + int32 threadsStopped; + get_sem_count(fRenderStoppedSem, &threadsStopped); + if (threadsStopped == fThreadCount) { TRACE("Done rendering!\n"); BMessage message(MSG_RENDER_COMPLETE); fMessenger.SendMessage(&message); @@ -145,9 +154,32 @@ void FractalEngine::WriteToBitmap(BBitmap* bitmap) B_RGB24); } +void FractalEngine::StopRender() +{ + if (fRenderStopped) + return; + fRenderStopped = true; + // true if another call to StopRender() won't work properly because + // the fRenderStoppedSem semaphores have already been acquired. + TRACE("Stopping render...\n"); + fStopRender = true; + for (uint i = 0; i(data); @@ -179,19 +203,12 @@ status_t FractalEngine::RenderThread(void* data) } } - bool restarting = false; while (true) { - TRACE("Thread %d starting another render pass\n", threadNum); - - if (!restarting) { - TRACE("Thread %d awaiting semaphore...\n", threadNum); - acquire_sem(engine->fRenderSem); - TRACE("Thread %d got semaphore!\n", threadNum); - } else { - TRACE("Thread %d setting restart = false\n", threadNum); - restarting = false; - } + release_sem(engine->fRenderStoppedSem); + TRACE("Thread %d awaiting semaphore...\n", threadNum); + acquire_sem(engine->fRenderSem); + TRACE("Thread %d got semaphore!\n", threadNum); uint16 width = engine->fWidth; uint16 height = engine->fHeight; @@ -213,17 +230,13 @@ status_t FractalEngine::RenderThread(void* data) // halfHeight-(halfHeight-1)-1 = 0 } - if (engine->fRestartRenderThread[threadNum]) { - TRACE("Thread %d Got restart message\n", threadNum); - - engine->fRestartRenderThread[threadNum] = false; - restarting = true; + if (engine->fStopRender) { + TRACE("Thread %d stopping\n", threadNum); break; // Restart the loop to update width, height, etc. } } - if (!restarting) { - engine->fRenderThreadRunning[threadNum] = false; + if (!engine->fStopRender) { BMessage message(FractalEngine::MSG_THREAD_RENDER_COMPLETE); message.AddUInt8("thread", threadNum); engine->PostMessage(&message); diff --git a/src/apps/mandelbrot/FractalEngine.h b/src/apps/mandelbrot/FractalEngine.h index be3e5a7b95..8411a1d3fa 100644 --- a/src/apps/mandelbrot/FractalEngine.h +++ b/src/apps/mandelbrot/FractalEngine.h @@ -50,10 +50,10 @@ private: uint8 fThreadCount; thread_id fRenderThreads[MAX_RENDER_THREADS]; sem_id fRenderSem; + sem_id fRenderStoppedSem; - uint8 fThreadsRendering; - bool fRestartRenderThread[MAX_RENDER_THREADS]; - bool fRenderThreadRunning[MAX_RENDER_THREADS]; + bool fStopRender; + bool fRenderStopped; double fLocationX; double fLocationY; @@ -66,6 +66,7 @@ private: int32 (FractalEngine::*fDoSet)(double real, double imaginary); void Render(double locationX, double locationY, double size); + void StopRender(); static status_t RenderThread(void* data); void RenderPixel(uint32 x, uint32 y);