From c894f63006a1cf10af3df9dc5363e4dd065c48e6 Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Sun, 7 Apr 2024 04:18:20 -0500 Subject: [PATCH] Finallt got multithreading to kind of work (?) --- includes/Events.h | 72 +++++++++++++++++----- includes/Window.h | 7 ++- includes/funcs.h | 28 +++++++-- source/Events.cpp | 152 +++++++++++++++++++++++++++++++++++----------- source/Window.cpp | 35 ++++++++--- source/funcs.cpp | 138 ++++++++++++++++++++++++++++++----------- source/main.cpp | 30 +++++++-- 7 files changed, 357 insertions(+), 105 deletions(-) diff --git a/includes/Events.h b/includes/Events.h index e941254..5f5dfa6 100644 --- a/includes/Events.h +++ b/includes/Events.h @@ -3,45 +3,87 @@ #define _NB_EVENTS #include +#include +#include +#include #include -#include +#include #include + +using state_register = std::atomic; + namespace NB { +void NULL_FUNC(); + class NBEvent { friend class NBEventListener; public: - NBEvent(void (*initFunc)(), uint64_t initMask, const char* initName=""); - + NBEvent(); + NBEvent(const uint64_t, void (*initFunc)() = NULL_FUNC, const char* initName=""); + NBEvent(const uint64_t, const char* initName=""); + NBEvent(NBEvent&); + NBEvent& operator=(NBEvent& cpy); + ~NBEvent(); + const std::string getName() const; const uint64_t getMask() const; void setMask(const uint64_t); void setName(const char*); void setFunc(void (*newFunc)()); - const uint64_t check(const uint64_t); + virtual const uint64_t check(const uint64_t) const; -private: +protected: + uint64_t mask = 0x0; + void (*func)() = nullptr; + std::string name = ""; + +}; + +class NBState : public NBEvent { +friend class NBEventListener; +public: + using NBEvent::NBEvent; + + const uint64_t check(const uint64_t) const override; + +}; + +enum NBStateChangeType : uint8_t { + STATE_RAISE, STATE_DROP, STATE_SET +}; + +struct NBStateChange { + uint8_t type; uint64_t mask; - void (*func)(); - std::string name; - }; class NBEventListener { public: - NBEventListener(NBEvent*, uint16_t, std::shared_ptr> initStatePtr=nullptr, uint64_t initState=0); + NBEventListener(NBEvent*, uint16_t, state_register* initStatePtr=nullptr, const uint64_t initState=(uint64_t)0x0); + template + NBEventListener(std::array eventArray, state_register* initStatePtr=nullptr, const uint64_t initState=(uint64_t)0x0) + : NBEventListener(eventArray.data(), eventArray.size(), initStatePtr, initState) {} NBEvent& operator[](int); - std::shared_ptr> getStatePtr(); - const uint64_t getState(); - const uint64_t raiseState(const uint64_t); + state_register* getStatePtr() const; + const uint64_t getState() const; + void raiseFlags(const uint64_t); + void raiseFlags(const NBEvent&); + void dropFlags(const uint64_t); + void dropFlags(const NBEvent&); + const bool snoop(const uint64_t) const; + const bool snoop(const NBEvent&) const; void setState(const uint64_t); - void check(); + void listen(); + void listen(const NBEvent&); -private: +protected: NBEvent* eventList; uint16_t numEvents; - std::shared_ptr> state; + state_register* state; + std::mutex bufferLock; + std::queue stateBuffer; }; diff --git a/includes/Window.h b/includes/Window.h index 60b3b76..7ac7b60 100644 --- a/includes/Window.h +++ b/includes/Window.h @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -13,6 +14,8 @@ class NBWindow { public: NBWindow(const std::array, const char*, GLFWmonitor* initMonitor=NULL, GLFWwindow* initWindow=NULL); NBWindow(const uint16_t, const uint16_t, const char*, GLFWmonitor* initMonitor=NULL, GLFWwindow* initWindow=NULL); + ~NBWindow(); + int init(); GLFWwindow* getWindow() const; @@ -21,7 +24,9 @@ public: void resize(const std::array); void resize(const uint16_t x, const uint16_t y); -private: +protected: + static std::atomic windowCount; + std::array windowSize; std::string windowName; bool ready=false, running=false; diff --git a/includes/funcs.h b/includes/funcs.h index ede8db3..c7a341e 100644 --- a/includes/funcs.h +++ b/includes/funcs.h @@ -8,12 +8,32 @@ #include "Window.h" #include "Events.h" -void framebuffer_callback(GLFWwindow* window, int width, int height); +enum EVENT : uint64_t { + A_PRESSED = (uint64_t)0x1, + B_PRESSED = (uint64_t)0x1 << 1, + CLOSE_WIND_SIG = (uint64_t)0x1 << 2, + CLOSE_PROG_SIG = (uint64_t)0x1 << 3, -void processInputs(GLFWwindow* window); + WINDOW_READY_A = (uint64_t)0x1 << 32, + WINDOW_READY_B = (uint64_t)0x1 << 33, + WINDOW_SHOULD_CLOSE = (uint64_t)0x1 << 34, + PROGRAM_SHOULD_CLOSE = (uint64_t)0x1 << 35 +}; -int renderingProcess(std::atomic&); +void framebuffer_callback(GLFWwindow*, int, int); -int consoleProcess(std::atomic&); +void processInputsA(); + +void processInputsB(); + +void windowClosedUser(GLFWwindow*); + +void stopWindows(); + +void waitForWindowClose(); + +int renderingProcessA(); + +int renderingProcessB(); #endif \ No newline at end of file diff --git a/source/Events.cpp b/source/Events.cpp index 4a56ba5..6625bb0 100644 --- a/source/Events.cpp +++ b/source/Events.cpp @@ -1,12 +1,34 @@ #include "Events.h" namespace NB { -NBEvent::NBEvent(void (*initFunc)(), const uint64_t initMask, const char* initName) { - mask = initMask; - func = initFunc; - name = initName; +std::invalid_argument null_mask_error("NULL MASK NOT ALLOWED"); + +void NULL_FUNC() {} + +NBEvent::NBEvent() {} + +NBEvent::NBEvent(const uint64_t initMask, void (*initFunc)(), const char* initName) : mask{initMask}, func{initFunc}, name{initName} { + if (mask == 0x0) { + throw null_mask_error; + } } +NBEvent::NBEvent(const uint64_t initMask, const char* initName) : NBEvent(initMask, NULL_FUNC, initName) {} + +NBEvent::NBEvent(NBEvent& cpy) : NBEvent(cpy.mask, cpy.func, cpy.name.c_str()) {} + +NBEvent& NBEvent::operator=(NBEvent& cpy) { + func = cpy.func; + name = cpy.name; + mask = cpy.mask; + if (mask==0x0) { + throw null_mask_error; + } + return *this; +} + +NBEvent::~NBEvent() {} + const uint64_t NBEvent::getMask() const { return mask; } @@ -15,33 +37,42 @@ const std::string NBEvent::getName() const { return name; } -void NBEvent::setMask(const uint64_t newMask) { - mask = newMask; -} -void NBEvent::setName(const char* newName) { - name = newName; -} - void NBEvent::setFunc(void (*newFunc)()) { func = newFunc; } -const uint64_t NBEvent::check(const uint64_t state) { - if (state & mask == mask) { - func(); - } - return state&(~mask); +void NBEvent::setMask(const uint64_t newMask) { + mask = newMask; } -NBEventListener::NBEventListener(NBEvent* initEventList, uint16_t initNum, std::shared_ptr> initStatePtr, uint64_t initState) { - if (initStatePtr == nullptr) { - state = std::shared_ptr>(new std::atomic); - } else { - state = initStatePtr; - } +void NBEvent::setName(const char* newName) { + name = newName; +} - *state = initState; +const uint64_t NBEvent::check(const uint64_t refState) const{ + if ((mask!=0) && ((refState&mask)==mask)) { + func(); + return refState&(~mask); + } + return refState; +} + +const uint64_t NBState::check(const uint64_t refState) const { + if ((mask!=0) && ((refState&mask)==mask)) { + func(); + } + return refState; +} + +NBEventListener::NBEventListener(NBEvent* initEventList, uint16_t initNum, state_register* initStatePtr, const uint64_t initState) + : stateBuffer() { + if (initStatePtr == nullptr) { + state = new state_register; + } + + std::atomic_store(state, initState); numEvents = initNum; + eventList = new NBEvent[numEvents]; for (uint16_t i = 0; i < initNum; ++i) { eventList[i] = initEventList[i]; } @@ -51,31 +82,80 @@ NBEvent& NBEventListener::operator[](int ind) { return eventList[ind % numEvents]; } -std::shared_ptr> NBEventListener::getStatePtr() { - return std::shared_ptr>(state); +state_register* NBEventListener::getStatePtr() const { + return state; } -const uint64_t NBEventListener::getState() { - return *state; +const uint64_t NBEventListener::getState() const { + return std::atomic_load(state); } -const uint64_t NBEventListener::raiseState(const uint64_t newState) { - uint64_t oldState = *state; - uint64_t tempState = oldState | newState; - *state = tempState; - return tempState; +void NBEventListener::raiseFlags(const uint64_t newState) { + bufferLock.lock(); + stateBuffer.push(NBStateChange{STATE_RAISE, newState}); + bufferLock.unlock(); +} + +void NBEventListener::raiseFlags(const NBEvent& newEvent) { + raiseFlags(newEvent.mask); +} + +void NBEventListener::dropFlags(const uint64_t dropState) { + bufferLock.lock(); + stateBuffer.push(NBStateChange{STATE_DROP, dropState}); + bufferLock.unlock(); +} + +void NBEventListener::dropFlags(const NBEvent& dropEvent) { + dropFlags(dropEvent.mask); +} + +const bool NBEventListener::snoop(const uint64_t refState) const { + return ((getState()&refState)==refState); +} + +const bool NBEventListener::snoop(const NBEvent& refEvent) const { + return snoop(refEvent.mask); } void NBEventListener::setState(const uint64_t newState) { - *state = newState; + bufferLock.lock(); + std::queue().swap(stateBuffer); + bufferLock.unlock(); + std::atomic_store(state, newState); } -void NBEventListener::check() { - uint64_t oldState = *state; +void NBEventListener::listen() { + uint64_t oldState = getState(); for (uint16_t i = 0; i < numEvents; ++i) { oldState = eventList[i].check(oldState); } - *state = oldState; + NBStateChange curr; + bufferLock.lock(); + for (; !stateBuffer.empty(); stateBuffer.pop()) { + curr = stateBuffer.front(); + switch (curr.type) { + case STATE_RAISE: + oldState |= curr.mask; + break; + case STATE_DROP: + oldState &= ~curr.mask; + break; + case STATE_SET: + oldState = curr.mask; + break; + default: + break; + } + } + bufferLock.unlock(); + setState(oldState); +} + +void NBEventListener::listen(const NBEvent& refEvent) { + uint64_t oldState = getState(); + oldState = refEvent.check(oldState); + setState(oldState); } }; \ No newline at end of file diff --git a/source/Window.cpp b/source/Window.cpp index 28ee24f..0385d8a 100644 --- a/source/Window.cpp +++ b/source/Window.cpp @@ -1,40 +1,57 @@ #include "Window.h" namespace NB { +std::atomic NBWindow::windowCount = 0; + NBWindow::NBWindow(const uint16_t x, const uint16_t y, const char* initName, GLFWmonitor* initMonitor, GLFWwindow* initWindow) { + if (windowCount == 0) { + glfwInit(); + } + windowSize = {x, y}; windowName = std::string(initName); monitor = initMonitor; shareWindow = initWindow; - glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - ready = true; + window = glfwCreateWindow(windowSize[0], windowSize[0], windowName.c_str(), monitor, shareWindow); + if (window == NULL) { + std::cout << "NB::NBWINDOW::COULD NOT CREATE WINDOW(" << windowName << ")\n"; + if (windowCount == 0) { glfwTerminate(); } + ready = false; + } else { + windowCount++; + ready = true; + } + } NBWindow::NBWindow(const std::array initSize, const char* initName, GLFWmonitor* initMonitor, GLFWwindow* initWindow) : NBWindow(initSize[0], initSize[1], initName, initMonitor, initWindow){} +NBWindow::~NBWindow() { + glfwSetWindowShouldClose(window, true); + glfwDestroyWindow(window); + windowCount--; + if (windowCount == 0) { + glfwTerminate(); + } +} + int NBWindow::init() { if (!ready) { std::cout << "NB::NBWINDOW::NOT READY\n"; return -1; } - window = glfwCreateWindow(windowSize[0], windowSize[0], windowName.c_str(), monitor, shareWindow); - if (window == NULL) { - std::cout << "NB::NBWINDOW::COULD NOT CREATE WINDOW\n"; - glfwTerminate(); - return -1; - } glfwMakeContextCurrent(window); if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) { std::cout << "NB::NBWINDOW::COULD NOT INITIALIZE GLAD\n"; - glfwTerminate(); + if (windowCount == 0) { glfwTerminate(); } return -1; } diff --git a/source/funcs.cpp b/source/funcs.cpp index 83d5e94..8a52bb8 100644 --- a/source/funcs.cpp +++ b/source/funcs.cpp @@ -1,57 +1,127 @@ #include "funcs.h" +void aPressAlert() { + std::cout << "A PRESSED!\n"; +} + +void bPressAlert() { + std::cout << "B PRESSED\n"; +} + +NB::NBEvent aKeyEvent(A_PRESSED, aPressAlert, "A_PRESSED"); +NB::NBEvent bKeyEvent(B_PRESSED, bPressAlert, "B_PRESSED"); +NB::NBEvent windowCloseEvent(CLOSE_WIND_SIG, stopWindows, "CLOSE_WINDOWS_SIG"); + +NB::NBState windowAIsReadyState(WINDOW_READY_A, "WINDOW_A_READY"); +NB::NBState windowBIsReadyState(WINDOW_READY_B, "WINDOW_B_READY"); +NB::NBState windowShouldCloseState(WINDOW_SHOULD_CLOSE, "WINDOW_CLOSING_STATE"); +NB::NBState programCloseState(PROGRAM_SHOULD_CLOSE, "PROGRAM_CLOSING_STATE"); + +std::array event_list= { + windowCloseEvent, + bKeyEvent, + aKeyEvent, + + windowAIsReadyState, + windowBIsReadyState, + windowShouldCloseState, + programCloseState +}; +NB::NBEventListener my_listener(event_list); + +NB::NBWindow* aWindow; +NB::NBWindow* bWindow; + void framebuffer_callback(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); } -void processInputs(GLFWwindow* window) { +void processInputsA() { + GLFWwindow* window = aWindow->getWindow(); if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { - glfwSetWindowShouldClose(window, true); + my_listener.raiseFlags(CLOSE_WIND_SIG); + } + if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) { + my_listener.raiseFlags(A_PRESSED); } } -int renderingProcess(std::atomic& shouldStop) { - std::cout << "Howdy from rendering!\n"; - NB::NBWindow mywindow(800, 600, "Multithreading?"); - mywindow.init(); - GLFWwindow* window = mywindow.getWindow(); +void processInputsB() { + GLFWwindow* window = bWindow->getWindow(); + if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { + my_listener.raiseFlags(CLOSE_WIND_SIG); + } + if (glfwGetKey(window, GLFW_KEY_B) == GLFW_PRESS) { + my_listener.raiseFlags(B_PRESSED); + } +} - glfwSetFramebufferSizeCallback(window, framebuffer_callback); +void windowClosedUser(GLFWwindow* windowToClose) { + my_listener.raiseFlags(CLOSE_WIND_SIG); +} - while(!glfwWindowShouldClose(window) && !shouldStop) { - processInputs(window); +void stopWindows() { + my_listener.raiseFlags(WINDOW_SHOULD_CLOSE); +} + +int renderingProcessA() { + std::cout << "Howdy from rendering A!\n"; + if ( aWindow->init() ) { return -1; } + + my_listener.raiseFlags(WINDOW_READY_A); + + glfwSetFramebufferSizeCallback(aWindow->getWindow(), framebuffer_callback); + glfwSetWindowCloseCallback(aWindow->getWindow(), windowClosedUser); + + uint64_t count = 0; + + while(!my_listener.snoop(WINDOW_SHOULD_CLOSE)) { + glfwMakeContextCurrent(aWindow->getWindow()); + processInputsA(); // glClearColor(r/255.0f, g/255.0f, b/255.0f, 1.0f); glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); - glfwPollEvents(); - glfwSwapBuffers(window); + //glfwPollEvents(); + glfwSwapBuffers(aWindow->getWindow()); + count++; } - shouldStop = true; - glfwSetWindowShouldClose(window, true); + my_listener.dropFlags(WINDOW_READY_A); + while(my_listener.snoop(WINDOW_READY_B)) {} + my_listener.raiseFlags(programCloseState); - glfwTerminate(); return 0; } -/* -int consoleProcess(std::atomic& shouldStop) { - char controlInput; - while(!shouldStop) { - std::cin >> controlInput; - switch (controlInput) { - case 'r': - r = (r==51)?0:51; - break; - case 'g': - g = (g==77)?0:77; - break; - case 'b': - b = (b==77)?0:77; - break; - default: - break; - } +int renderingProcessB() { + std::cout << "Howdy from rendering B!\n"; + + if ( bWindow->init() ) { return -1; } + + my_listener.raiseFlags(WINDOW_READY_B); + + glfwSetFramebufferSizeCallback(bWindow->getWindow(), framebuffer_callback); + glfwSetWindowCloseCallback(bWindow->getWindow(), windowClosedUser); + + uint64_t count = 0; + + while(!my_listener.snoop(WINDOW_SHOULD_CLOSE)) { + //std::cout << "WINDOW B FRAME\t" << count << "\n"; + glfwMakeContextCurrent(bWindow->getWindow()); + processInputsB(); + + glClearColor(0.3f, 0.2f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + //glfwPollEvents(); + glfwSwapBuffers(bWindow->getWindow()); + count++; } -}*/ \ No newline at end of file + my_listener.dropFlags(WINDOW_READY_B); + std::cout << "DONE RENDERING B\n"; + while(my_listener.snoop(WINDOW_READY_A)) {} + my_listener.raiseFlags(programCloseState); + + return 0; +} \ No newline at end of file diff --git a/source/main.cpp b/source/main.cpp index 2ceca5e..416f12d 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -7,17 +7,35 @@ #include "funcs.h" #include "shader.h" +extern NB::NBWindow* aWindow; +extern NB::NBWindow* bWindow; +extern NB::NBEventListener my_listener; int main() { std::cout << "Hello World!\n"; - // std::shared_ptr> shouldClose(new std::atomic); - // *shouldClose = false; - //std::atomic r=51, g=77, b=77; - std::atomic shouldClose= false; +{ + NB::NBWindow windowa(800, 600, "Multithreading?"); + NB::NBWindow windowb(800, 600, "Multithreading!"); + aWindow = &windowa; + bWindow = &windowb; - std::thread renderingThread(renderingProcess, std::ref(shouldClose)); + glfwMakeContextCurrent(NULL); + std::thread renderingThreadA(renderingProcessA); + std::thread renderingThreadB(renderingProcessB); - renderingThread.join(); + renderingThreadB.detach(); + renderingThreadA.detach(); + + while(!my_listener.snoop(PROGRAM_SHOULD_CLOSE)) { + glfwPollEvents(); + my_listener.listen(); + } + std::cout << "YOUVE REACHED THE END OF THE MAIN THREAD!\n"; + +} + + state_register* state = my_listener.getStatePtr(); + delete state; return 0; } \ No newline at end of file