昨日寝る前に、お酒など飲みながら、なんとなく、先ほどの関数を分離してみました。
// // スレッド プロシージャ // void Screen::threadProc(ThreadNotifier& iNotifier) { // コア数取得 const auto aProcessors = SystemInfoHelper::getProcessors(); // 描画スレッド構築 std::vector<TaskThread> aTaskThreads; aTaskThreads.reserve(aProcessors); for (std::uint32_t aCt = 0; aCt < aProcessors; aCt++) { // スレッド構築 std::shared_ptr<Thread> aThread(new Thread()); std::shared_ptr<Event> aBeginEvent(new Event()), aEndEvent(new Event()); TaskThread aTaskThread = { aThread, aBeginEvent, aEndEvent }; aTaskThreads.push_back(aTaskThread); // スレッド開始 aThread->start(createDrawerThreadProc(aBeginEvent, aEndEvent)); } // 描画ループ while (!iNotifier.isStopRequestIssued()) { try { auto aLock = pforce::lock(mDrawerThreadCriticalSection); if (mPrimaryScreen->isDirty()) { // 描画準備 mTaskInfo.reset(mPrimaryScreen); auto aScreenLock = pforce::lock(*mTaskInfo.screen); // 描画開始 std::for_each(aTaskThreads.begin(), aTaskThreads.end(), [](TaskThread& iThread) { iThread.beginEvent->set(); }); // 描画終了 std::for_each(aTaskThreads.begin(), aTaskThreads.end(), [](TaskThread& iThread) { iThread.endEvent->wait(INFINITE), iThread.endEvent->reset(); }); } } catch (std::exception&) { // do nothing. } #if defined(PFORCE_STRESS_TEST) // ストレス テストの場合はスリープしない。 #else iNotifier.sleep(1); #endif } // 描画スレッド終了 mTaskInfo.reset(); std::for_each(aTaskThreads.begin(), aTaskThreads.end(), [](TaskThread& iThread) { iThread.thread->invalidate(), iThread.beginEvent->set(); }); std::for_each(aTaskThreads.begin(), aTaskThreads.end(), [](TaskThread& iThread) { iThread.thread->stop(); }); } // // 描画スレッド プロシージャを生成する。 // const ThreadFunction Screen::createDrawerThreadProc(const std::shared_ptr<Event> iBeginEvent, const std::shared_ptr<Event> iEndEvent) { // 合成バッファ構築 const auto aRowbytes = ImageHelper::getRowbytes(mPrimaryScreen->getWidth(), imageB8G8R8X8); auto aPixelData = MemoryHelper::alloc<std::uint8_t>(aRowbytes * mPrimaryScreen->getBandHeight()); std::shared_ptr<IImage> aImage(new Image(mPrimaryScreen->getWidth(), mPrimaryScreen->getBandHeight(), imageB8G8R8X8, aRowbytes, aPixelData)); // 描画スレッド プロシージャ auto aDrawerThreadProc = [this, iBeginEvent, iEndEvent, aImage](ThreadNotifier& iNotifier) -> void { while (!iNotifier.isStopRequestIssued()) { iBeginEvent->wait(INFINITE), iBeginEvent->reset(); try { if (mTaskInfo.screen) { // 描画 auto aScreen = mTaskInfo.screen.get(); const auto aMax = aScreen->getBandCount(); const auto aBandHeight = aScreen->getBandHeight(); for (;;) { const auto aBandIndex = mTaskInfo.getTargetBandIndex(); if (aBandIndex < aMax) { // 描画 Rect aDirtyArea = aScreen->getDirtyArea(aBandIndex); if (!RectHelper::isEmpty(aDirtyArea)) { aScreen->draw(*aImage, aBandIndex); // 表画面へ転送 auto aLock = pforce::lock(mTaskInfo.cs); // GDI はスレッドセーフでないため転送はシーケンシャルに実施 blitImageToDeviceContext(mDeviceContext, *aImage, aDirtyArea, aBandIndex * aBandHeight); } } else { // 終了 break; } } } } catch (std::exception&) { // do nothing. } iEndEvent->set(); } }; return aDrawerThreadProc; }
うん。こっちの方が意味の通りが良い気がしますね。
さて、次の更新の時にはもうちょっと前進しようかな。