diff --git a/GPA675Lab1GOL/GOLTeamH.cpp b/GPA675Lab1GOL/GOLTeamH.cpp index 00d903a..f2b8fc2 100644 --- a/GPA675Lab1GOL/GOLTeamH.cpp +++ b/GPA675Lab1GOL/GOLTeamH.cpp @@ -1,11 +1,9 @@ #include "GOLTeamH.h" - - -//Inlining des acesseur dans GOLTeam.h - - - +GOLTeamH::GOLTeamH() + : mParsedRule{} +{ +} //! \brief Accesseurs retournant des informations générales sur la //! simulation en cours. @@ -146,7 +144,7 @@ bool GOLTeamH::setRule(std::string const& rule) { mRule = rule; bool firstPart{ true }; - uint16_t parsedRuleRevive{}, parsedRuleSurvive{}; + uint32_t parsedRule{}; // On vérifie que la chaine de charactères contient un B au début. // 5 = taille minimale @@ -160,9 +158,9 @@ bool GOLTeamH::setRule(std::string const& rule) // Si c'est un chiffre, on continue en enregistrant la valeur. if (opt.has_value()) { if (firstPart) - parsedRuleRevive |= 1u << opt.value(); + parsedRule |= 1u << opt.value(); else - parsedRuleSurvive |= 1u << opt.value(); + parsedRule |= 1u << (opt.value() + 16); continue; } @@ -179,8 +177,7 @@ bool GOLTeamH::setRule(std::string const& rule) return false; } - mParsedRuleRevive = parsedRuleRevive; - mParsedRuleSurvive = parsedRuleSurvive; + mParsedRule |= parsedRule; return true; } @@ -384,56 +381,61 @@ void GOLTeamH::processOneStep() if (mBorderManagement == GOL::BorderManagement::foreverDead) { size_t aliveCount{}; size_t offset{ width() + 2 }; - auto* ptrGrid{ &grid[0] }; // Pointeur qui se promène en mémoire. - auto* const ptrGridInt{ &intGrid[0] }; // Pointeur statique pour des calculs. + auto width{ mData.width() }, height{ mData.height() }; - for (size_t i{}; i < mData.realSize() - offset - 1; ++i) { + // Index commence à la première case qui n'est pas dans le border + auto* ptrGridInt{ &intGrid[width + 3] }; // Pointeur du tableau intermédiaire. + auto* ptrGrid{ &grid[width + 3] }; // Pointeur qui se promène en mémoire. - if (mData.isInBorder(i)) { + for (size_t j{}; j < height; ++j) { + for (size_t i{}; i < width; ++i) { + + aliveCount = 0; + + // Top + ptrGrid -= offset + 1; + aliveCount += static_cast (*ptrGrid); ptrGrid++; - continue; + aliveCount += static_cast (*ptrGrid); + ptrGrid++; + aliveCount += static_cast (*ptrGrid); + + // Milieu + ptrGrid += offset - 2; + aliveCount += static_cast (*ptrGrid); + ptrGrid += 2; + aliveCount += static_cast (*ptrGrid); + + + // Dessous + ptrGrid += offset - 2; + aliveCount += static_cast (*ptrGrid); + ptrGrid++; + aliveCount += static_cast (*ptrGrid); + ptrGrid++; + aliveCount += static_cast (*ptrGrid); + + // On retourne à une place plus loin qu'à l'origine. + ptrGrid -= offset; + ptrGridInt++; + + // On prend avantage du fait que GOL::State::alive = 1. + // + // On évite aussi d'utiliser l'opérateur []. En profilant, nous avons vu un + // impact de performance de ~5%. + // + // On accède à la bonne partie des bits et on compare si le bit de survie/réanimation est + // présent. Voir GOLTeamH.cpp pour plus de détails. + *(ptrGridInt - 1) = static_cast( + static_cast( + (mParsedRule >> static_cast(*(ptrGrid - 1)) * 16) & (1u << aliveCount) + ) + ); } - aliveCount = 0; - - // On prend avantage du fait que GOL::State::alive = 1 et donc - // on retire des branches if. - - // Top - ptrGrid -= offset + 1; - aliveCount += static_cast (*ptrGrid); - ptrGrid++; - aliveCount += static_cast (*ptrGrid); - ptrGrid++; - aliveCount += static_cast (*ptrGrid); - - // Milieu - ptrGrid += offset - 2; - aliveCount += static_cast (*ptrGrid); + // On saute le border ptrGrid += 2; - aliveCount += static_cast (*ptrGrid); - - - // Dessous - ptrGrid += offset - 2; - aliveCount += static_cast (*ptrGrid); - ptrGrid++; - aliveCount += static_cast (*ptrGrid); - ptrGrid++; - aliveCount += static_cast (*ptrGrid); - - // On retourne à une place plus loin qu'à l'origine. - ptrGrid -= offset; - - // On prend avantage du fait que GOL::State::alive = 1. - // - // On évite aussi d'utiliser l'opérateur []. En profilant, nous avons vu un - // impact de performance de ~5%. - if (*(ptrGrid - 1) == GOL::State::alive) - *(ptrGridInt + i) = static_cast(static_cast(mParsedRuleSurvive & (1u << aliveCount))); - else - *(ptrGridInt + i) = static_cast(static_cast(mParsedRuleRevive & (1u << aliveCount))); - + ptrGridInt += 2; } ptrGrid = nullptr; @@ -483,31 +485,31 @@ void GOLTeamH::updateImage(uint32_t* buffer, size_t buffer_size) const return; auto s_ptr = buffer; - auto e_ptr = &buffer[buffer_size]; + auto& grid = mData.data(); + auto width{ mData.width() }, height{ mData.height() }; + auto* ptrGrid{ &grid[width + 3] }; // Pointeur qui se promène en mémoire. // On itère sur chaque éléments du tableau et on associe la couleur. - for (size_t index{ width() + 2 }; // On ignore la ligne du bas. - index < (width() + 2) * (height() + 1); // On ignore la ligne du haut. - index++) { + for (size_t j{}; j < height; ++j) { + for (size_t i{}; i < width; ++i) { + auto var = static_cast(*ptrGrid); - if (mData.isInBorder(index)) - continue; + *s_ptr &= 0; // Clear + *s_ptr |= MAX_ALPHA << 24; // Alpha = 255 - auto var = static_cast(grid[index]); + *s_ptr |= mAliveColor.red * var << 16; + *s_ptr |= mAliveColor.green * var << 8; + *s_ptr |= mAliveColor.blue * var; - *s_ptr &= 0; // Clear - *s_ptr |= MAX_ALPHA << 24; // Alpha = 255 + *s_ptr |= mDeadColor.red * (1 - var) << 16; + *s_ptr |= mDeadColor.green * (1 - var) << 8; + *s_ptr |= mDeadColor.blue * (1 - var); - *s_ptr |= mAliveColor.red * var << 16; - *s_ptr |= mAliveColor.green * var << 8; - *s_ptr |= mAliveColor.blue * var; - - *s_ptr |= mDeadColor.red * (1 - var) << 16; - *s_ptr |= mDeadColor.green * (1 - var) << 8; - *s_ptr |= mDeadColor.blue * (1 - var); - - s_ptr++; + s_ptr++; + ptrGrid++; + } + ptrGrid += 2; } } diff --git a/GPA675Lab1GOL/GOLTeamH.h b/GPA675Lab1GOL/GOLTeamH.h index d57ed8c..f41ee24 100644 --- a/GPA675Lab1GOL/GOLTeamH.h +++ b/GPA675Lab1GOL/GOLTeamH.h @@ -12,6 +12,8 @@ constexpr unsigned char MAX_ALPHA = 255; class GOLTeamH : public GOL { public: + GOLTeamH(); + // inline puisque trivial. size_t width() const override { return mData.width(); } size_t height() const override { return mData.height(); } @@ -43,7 +45,14 @@ private: // On utilise un bitset qui contient les règles de chaque nombre. // On n'utilise pas std::bitset pour des raisons de performance. - uint16_t mParsedRuleRevive, mParsedRuleSurvive; + // + // Le premier 8 bits (à gauche) est celui de la règle de survie alors + // qu'à droite nous avons la règle de réanimation. + // 0000000111000111 0000000110011001 + // ^^^^^^^ ^^^^^^^ + // Bits non utilisés + // + uint32_t mParsedRule; GridTeamH mData; Color mDeadColor, mAliveColor; diff --git a/GPA675Lab1GOL/GridTeamH.h b/GPA675Lab1GOL/GridTeamH.h index dd8fa71..0c5050b 100644 --- a/GPA675Lab1GOL/GridTeamH.h +++ b/GPA675Lab1GOL/GridTeamH.h @@ -83,7 +83,7 @@ private: }; // Attention: performance terrible si utilisation. Seulement lorsque vitesse -// n'est pas demandée. +// n'est pas demandée, donc pas dans la boucle principale. inline bool GridTeamH::isInBorder(size_t index) const { return(index % (mWidth + 2) < 1