From 1c7a9900befc869f2f5df043741cf67a0ef8747a Mon Sep 17 00:00:00 2001 From: Seth Hamilton Date: Fri, 5 Sep 2025 11:21:34 -0500 Subject: [PATCH] pool allocation. not working. not sure why. will travel back in time... --- LivePlotter.vcxproj | 12 ++-- LivePlotter.vcxproj.filters | 4 +- Test.vcxproj | 2 +- Test.vcxproj.filters | 2 +- Test.vcxproj.user | 9 ++- inc/body.hpp | 12 +++- inc/sync.hpp | 22 ++++-- src/body.cpp | 56 +++++++--------- src/demo.cpp | 6 +- src/live_plotter.cpp | 129 ++++++++++++++++++++---------------- 10 files changed, 145 insertions(+), 109 deletions(-) diff --git a/LivePlotter.vcxproj b/LivePlotter.vcxproj index ccf4e96..b40c75b 100644 --- a/LivePlotter.vcxproj +++ b/LivePlotter.vcxproj @@ -1,4 +1,4 @@ - + @@ -186,7 +186,7 @@ xcopy /y "$(ProjectDir)src\shaders\vertex.glsl" "$(OutDir)" - xcopy /y "$(ProjectDir)poses.csv" "$(OutDir)" && xcopy /y "$(ProjectDir)src\shaders\vertex.glsl" "$(OutDir)" && xcopy /y "$(ProjectDir)src\shaders\fragment.glsl" "$(OutDir)" + xcopy /y "$(ProjectDir)assets\Icosphere.obj" "$(OutDir)" && xcopy /y "$(ProjectDir)assets\poses.csv" "$(OutDir)" && xcopy /y "$(ProjectDir)src\shaders\vertex.glsl" "$(OutDir)" && xcopy /y "$(ProjectDir)src\shaders\fragment.glsl" "$(OutDir)" @@ -209,7 +209,7 @@ xcopy /y "$(ProjectDir)src\shaders\vertex.glsl" "$(OutDir)" - xcopy /y "$(ProjectDir)poses.csv" "$(OutDir)" && xcopy /y "$(ProjectDir)src\shaders\vertex.glsl" "$(OutDir)" && xcopy /y "$(ProjectDir)src\shaders\fragment.glsl" "$(OutDir)" + xcopy /y "$(ProjectDir)assets\Icosphere.obj" "$(OutDir)" && xcopy /y "$(ProjectDir)assets\poses.csv" "$(OutDir)" && xcopy /y "$(ProjectDir)src\shaders\vertex.glsl" "$(OutDir)" && xcopy /y "$(ProjectDir)src\shaders\fragment.glsl" "$(OutDir)" @@ -233,7 +233,7 @@ true - xcopy /y "$(ProjectDir)poses.csv" "$(OutDir)" && xcopy /y "$(ProjectDir)src\shaders\vertex.glsl" "$(OutDir)" && xcopy /y "$(ProjectDir)src\shaders\fragment.glsl" "$(OutDir)" + xcopy /y "$(ProjectDir)assets\Icosphere.obj" "$(OutDir)" && xcopy /y "$(ProjectDir)assets\poses.csv" "$(OutDir)" && xcopy /y "$(ProjectDir)src\shaders\vertex.glsl" "$(OutDir)" && xcopy /y "$(ProjectDir)src\shaders\fragment.glsl" "$(OutDir)" @@ -242,16 +242,16 @@ - + + - diff --git a/LivePlotter.vcxproj.filters b/LivePlotter.vcxproj.filters index 17e4515..d71a56f 100644 --- a/LivePlotter.vcxproj.filters +++ b/LivePlotter.vcxproj.filters @@ -30,7 +30,7 @@ Source Files - + Source Files @@ -53,7 +53,7 @@ Header Files - + Header Files diff --git a/Test.vcxproj b/Test.vcxproj index 3b1ae79..0a27a9e 100644 --- a/Test.vcxproj +++ b/Test.vcxproj @@ -20,7 +20,7 @@ - + diff --git a/Test.vcxproj.filters b/Test.vcxproj.filters index 7cf2e47..01fd40c 100644 --- a/Test.vcxproj.filters +++ b/Test.vcxproj.filters @@ -18,7 +18,7 @@ Source Files - + Source Files diff --git a/Test.vcxproj.user b/Test.vcxproj.user index 88a5509..a5ee18c 100644 --- a/Test.vcxproj.user +++ b/Test.vcxproj.user @@ -1,4 +1,11 @@  - + + $(OutDir) + WindowsLocalDebugger + + + $(OutDir) + WindowsLocalDebugger + \ No newline at end of file diff --git a/inc/body.hpp b/inc/body.hpp index c22c247..9214bc9 100644 --- a/inc/body.hpp +++ b/inc/body.hpp @@ -5,16 +5,22 @@ #include #include "util.hpp" +struct ObjData { + float* verts; + int verts_len; + int* faces; + int faces_len; +}; + struct Body { glm::mat4 pose; + glm::vec4 color; float scale; uint ebo; uint vao; uint vbo; uint shader; - std::vector verts; - std::vector faces; - glm::vec4 color; + ObjData data; }; bool load_body(Body* out_body, std::string filepath); diff --git a/inc/sync.hpp b/inc/sync.hpp index 593993d..aa4b9b1 100644 --- a/inc/sync.hpp +++ b/inc/sync.hpp @@ -15,9 +15,15 @@ typedef LARGE_INTEGER TimeSpan; typedef DWORD (WINAPI *ThreadFunc)(_In_ LPVOID lpParameter); typedef LPVOID ThreadArg; -const TimeSpan infinite_ts = LLONG_MAX; -static const LARGE_INTEGER freq; -QueryPerformanceFrequency(&freq); +const TimeSpan infinite_ts = { .QuadPart = LLONG_MAX }; + +LARGE_INTEGER _init_freq() { + LARGE_INTEGER freq; + QueryPerformanceFrequency(&freq); + return freq; +} + +static LARGE_INTEGER freq = _init_freq(); #endif Thread make_thread(ThreadFunc t, ThreadArg a); @@ -60,7 +66,7 @@ Thread make_thread(ThreadFunc f, ThreadArg a) { } void join(Thread t) { - WaitForSingleObject(t, infinite_ts); + WaitForSingleObject(t, INFINITE); } Mutex make_mutex() { @@ -92,7 +98,11 @@ ConditionVar make_condition_var() { } void wait(ConditionVar &c, Mutex &m, TimeSpan ts) { - SleepConditionVariableCS(&c, &m, ts); + if (ts.QuadPart == infinite_ts.QuadPart) { + SleepConditionVariableCS(&c, &m, INFINITE); + } else { + SleepConditionVariableCS(&c, &m, static_cast(to_ms(ts))); + } } void wake_one(ConditionVar &c) { @@ -112,7 +122,7 @@ Semaphore make_semaphore(int initial, int max) { } void wait(Semaphore &s) { - WaitForSingleObject(s, infinite_ts); + WaitForSingleObject(s, INFINITE); } void post(Semaphore &s) { diff --git a/src/body.cpp b/src/body.cpp index dbbeb80..03521d0 100644 --- a/src/body.cpp +++ b/src/body.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include "util.hpp" #include "body.hpp" @@ -17,29 +16,24 @@ enum class ParserState { FACE_SKIP, }; -static map, vector>> cache; +static map cache; -optional, vector>> _parse_obj(const char* obj_filepath); +bool _parse_obj(ObjData* data, const char* obj_filepath); bool load_body(Body* out_body, const char* obj_filepath) { - vector verts; - vector faces; - + ObjData data; if (auto it = cache.find(obj_filepath); it != cache.end()) { - verts = it->second.first; - faces = it->second.second; - } else if (auto pair = _parse_obj(obj_filepath); pair.has_value()) { - verts = pair.value().first; - faces = pair.value().second; - cache[obj_filepath] = pair.value(); + data = it->second; + } else if (_parse_obj(&data, obj_filepath)) { + cache[obj_filepath] = data; } else { return false; } // Need a good validation check here. This is a stand in. - if (verts.size() == 0 || faces.size() == 0) { - printf( - "Obj file appears incomplete or corrupted. Num verts %zu. Num Faces %zu.\n", verts.size(), faces.size()); + if (data.verts_len == 0 || data.faces_len == 0) { + printf("Obj file appears incomplete or corrupted. Num verts %d. Num Faces %d.\n", data.verts_len, + data.faces_len); return false; } @@ -55,22 +49,15 @@ bool load_body(Body* out_body, const char* obj_filepath) { glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(float), &verts[0], GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, data.verts_len * sizeof(float), data.verts, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, faces.size() * sizeof(int), &faces[0], GL_STATIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.faces_len * sizeof(int), &data.faces, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); - out_body->pose = glm::mat4(1); - out_body->ebo = ebo; - out_body->vao = vao; - out_body->vbo = vbo; - out_body->shader = 0; - out_body->verts = verts; - out_body->faces = faces; - + *out_body = { .pose = glm::mat4(1), .ebo = ebo, .vao = vao, .vbo = vbo, .shader = 0, .data = data }; return true; } @@ -79,7 +66,7 @@ void draw_body(const Body& b) { set_uniform(b.shader, "global_t", glm::scale(b.pose, glm::vec3(b.scale))); set_uniform(b.shader, "color", b.color); glBindVertexArray(b.vao); - glDrawElements(GL_TRIANGLES, b.faces.size(), GL_UNSIGNED_INT, 0); + glDrawElements(GL_TRIANGLES, b.data.faces_len, GL_UNSIGNED_INT, 0); } void create_new_sphere(Body* b, float scale) { @@ -87,7 +74,8 @@ void create_new_sphere(Body* b, float scale) { b->scale = scale; } -optional, vector>> _parse_obj(const char* obj_filepath) { +// I need to write a good obj file parser at some point. This is basically garbage +bool _parse_obj(ObjData* data, const char* obj_filepath) { string source; if (!read_file(&source, obj_filepath)) { return {}; @@ -103,8 +91,11 @@ optional, vector>> _parse_obj(const char* obj_filepath) } } - vector verts; - vector faces; + float* verts = (float*)malloc(sizeof(float) * num_verts * 3); + int* faces = (int*)malloc(sizeof(int) * num_faces * 3); + + int vert_i = 0; + int face_i = 0; // Get ready for the parsing loop ParserState state = ParserState::PREFIX; @@ -123,14 +114,14 @@ optional, vector>> _parse_obj(const char* obj_filepath) break; case ParserState::VERTEX: if (iswspace(source[i])) { - verts.push_back(atof(&source[start])); + verts[vert_i++] = atof(&source[start]); start = i + 1; } break; case ParserState::FACE: if (source[i] == '/') { state = ParserState::FACE_SKIP; - faces.push_back(atoi(&source[start]) - 1); + faces[face_i++] = atoi(&source[start]) - 1; } break; case ParserState::FACE_SKIP: @@ -144,4 +135,7 @@ optional, vector>> _parse_obj(const char* obj_filepath) continue; } } + + *data = { .verts = verts, .verts_len = vert_i, .faces = faces, .faces_len = face_i }; + return true; } diff --git a/src/demo.cpp b/src/demo.cpp index 0fd7d63..9d1a806 100644 --- a/src/demo.cpp +++ b/src/demo.cpp @@ -66,6 +66,9 @@ int main() { } start(800, 800); + pointid id = create_point(0, 0, 0); + set_color(id, 1, 1, 1); + set_scale(id, 10); while (true) ; @@ -84,7 +87,8 @@ int main() { // vector words = split_str(line, ' '); // if (!words.size() == 4) // return NULL; - // printf("Received: %s, %s, %s, %s\n", words[0], words[1], words[2], words[3]); // echo for debugging + // printf("Received: %s, %s, %s, %s\n", words[0].c_str(), words[1].c_str(), words[2].c_str(), + // words[3].c_str()); // echo for debugging // string name = words[0]; // float x = stof(words[1]); // float y = stof(words[2]); diff --git a/src/live_plotter.cpp b/src/live_plotter.cpp index ca6a61e..24df280 100644 --- a/src/live_plotter.cpp +++ b/src/live_plotter.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -5,9 +6,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -16,9 +15,7 @@ #include #include #include -#include #include -#include #include "sync.hpp" #include "util.hpp" @@ -27,13 +24,18 @@ #include "camera.hpp" #include "live_plotter.hpp" -#define LERP_MOVE_PERIOD_S 0.05 -#define STOP_WAIT_TIME_MS 500 - using namespace sync; +// Constants +const char* vertex_filepath = "vertex.glsl"; +const char* fragment_filepath = "fragment.glsl"; +const float lerp_move_period_s = 0.05; +const int stop_wait_time_ms = 500; +const int max_point_mem = 10 << 20; // bytes + struct Point { bool initialized; + bool replaceable; glm::vec3 startloc; glm::vec3 targetloc; Body b; @@ -51,13 +53,11 @@ static Thread t; static Mutex m; static uint shader; static LARGE_INTEGER fr; -static pointid next_id = 0; -static std::map id_to_point; // Use a pool allocator possibly later -static std::map point_to_id; -// Constants -const char* vertex_filepath = "vertex.glsl"; -const char* fragment_filepath = "fragment.glsl"; +constexpr int point_buf_len + = max_point_mem / sizeof(Point); // ~max_point_mem bytes of points. does not include vertex data for obj +static Point* point_buf = (Point*)malloc(point_buf_len * sizeof(Point)); +static int point_buf_i = 0; // Private foward decls void _resize_cb(GLFWwindow* win, int w, int h); @@ -77,6 +77,10 @@ extern DllExport bool __cdecl start(int win_w, int win_h) { m = make_mutex(); + for (int i = 0; i < point_buf_len; i++) { + point_buf[i].replaceable = true; + } + if (!QueryPerformanceFrequency(&fr)) { printf("Failed to get the performance counter frequency.\n"); return false; @@ -95,72 +99,81 @@ extern DllExport bool __cdecl start(int win_w, int win_h) { extern DllExport bool __cdecl stop() { stop_flag = true; - DWORD res = WaitForSingleObject(t, STOP_WAIT_TIME_MS); + DWORD res = WaitForSingleObject(t, stop_wait_time_ms); bool success = res == WAIT_OBJECT_0; running = !success; // Consider the app still running if we didn't shut down properly...? // TODO: Please wrap away win api synch stuff. thank you - if (!running) dispose(m); + if (!running) + dispose(m); return success; } -extern DllExport pointid __cdecl create_point(float x, float y, float z) { +extern DllExport pointid __cdecl create_point(float x, float y, float z) { lock(m); - Point* p = (Point*)malloc(sizeof(Point)); - *p = { + + // This is stupid. Please fix + int slot = -1; + int start_loc = point_buf_i; + do { + if (point_buf[point_buf_i % point_buf_len].replaceable) { + slot = point_buf_i % point_buf_len; + break; + } + point_buf_i++; + } while (point_buf_i != start_loc); + + assert(slot > -1); + + point_buf[slot] = { .initialized = false, + .replaceable = false, .startloc = glm::vec3(x, y, z), .targetloc = glm::vec3(x, y, z), .lifetime_s = INFINITY, - .start_s = _time() + .start_s = _time() }; - p->b.scale = 1.0f; - p->b.color = glm::vec4(randf() + 0.1, randf() + 0.1, randf() + 0.1, 1); + point_buf[slot].b.scale = 1.0f; + point_buf[slot].b.color = glm::vec4(randf() + 0.1, randf() + 0.1, randf() + 0.1, 1); - pointid id = next_id++; - id_to_point[id] = p; - point_to_id[p] = id; unlock(m); - return id; + return slot; } -extern DllExport void __cdecl set_color(pointid id, float r, float g, float b) { +extern DllExport void __cdecl set_color(pointid id, float r, float g, float b) { lock(m); - Point* p = id_to_point[id]; - p->b.color = { r, g, b, p->b.color[3] }; + Point &p = point_buf[id % point_buf_len]; + p.b.color = { r, g, b, p.b.color[3] }; unlock(m); } extern DllExport void __cdecl set_scale(pointid id, float scale) { lock(m); - Point* p = id_to_point[id]; - p->b.scale = scale; + Point &p = point_buf[id % point_buf_len]; + p.b.scale = scale; unlock(m); } extern DllExport void __cdecl update_point(pointid id, float x, float y, float z) { lock(m); - Point* p = id_to_point[id]; - p->targetloc = { x, y, z }; - p->startloc = p->b.pose[3]; - p->start_s = _time(); + Point &p = point_buf[id % point_buf_len]; + p.targetloc = { x, y, z }; + p.startloc = p.b.pose[3]; + p.start_s = _time(); unlock(m); } extern DllExport void __cdecl set_lifetime(pointid id, float new_lifetime_s) { lock(m); - Point* p = id_to_point[id]; - p->start_s = _time(); - p->lifetime_s = new_lifetime_s; + Point &p = point_buf[id % point_buf_len]; + p.start_s = _time(); + p.lifetime_s = new_lifetime_s; unlock(m); } extern DllExport void __cdecl clear_point(pointid id) { lock(m); - Point* p = id_to_point[id]; - id_to_point.erase(id); - point_to_id.erase(p); - free(p); + point_buf[id % point_buf_len].replaceable = true; unlock(m); } @@ -192,7 +205,7 @@ void _scroll_cb(GLFWwindow* win, double xoffset, double yoffset) { zoom_camera(c DWORD _win_thread(LPVOID args) { glm::vec2* winsize = (glm::vec2*)args; - camera = make_camera({ 0, 0, 0 }, 3000); + camera = make_camera({ 0, 0, 0 }, 10); camera.theta = glm::radians(90.0f); camera.phi = glm::radians(30.0f); viewport = make_viewport(winsize->x, winsize->y, 45.0f); @@ -255,26 +268,29 @@ void _refresh_win() { set_uniform(shader, "projection_t", camera_to_projection(viewport)); if (trylock(m)) { - for (const auto& [id, p] : id_to_point) { + for (int i = 0; i < point_buf_len; i++) { + Point &p = point_buf[i]; + if (p.replaceable) continue; + // Initialize if not done so yet - if (!p->initialized) { - create_new_sphere(&p->b, p->b.scale); - p->b.shader = shader; - p->b.pose = glm::translate(glm::mat4(1), p->startloc); - p->initialized = true; + if (!p.initialized) { + create_new_sphere(&p.b, p.b.scale); + p.b.shader = shader; + p.b.pose = glm::translate(glm::mat4(1), p.startloc); + p.initialized = true; } // Perform fade - double elapsed_time_s = _time() - p->start_s; - float t = elapsed_time_s / p->lifetime_s; - t = std::clamp(t, 0.0f, 1.0f); - p->b.color.w = lerp(1.0, 0.0, t); + double elapsed_time_s = _time() - p.start_s; + float t = elapsed_time_s / p.lifetime_s; + t = glm::clamp(t, 0.0f, 1.0f); + p.b.color.w = lerp(1.0, 0.0, t); // Lerp position - t = elapsed_time_s / LERP_MOVE_PERIOD_S; - t = std::clamp(t, 0.0f, 1.0f); - p->b.pose[3] = glm::vec4(lerp(p->startloc, p->targetloc, t), 1); - draw_body(p->b); + t = elapsed_time_s / lerp_move_period_s; + t = glm::clamp(t, 0.0f, 1.0f); + p.b.pose[3] = glm::vec4(lerp(p.startloc, p.targetloc, t), 1); + draw_body(p.b); } unlock(m); } @@ -290,4 +306,3 @@ double _time() { } return (double)timeticks.QuadPart / (double)fr.QuadPart; } -