Implement threading
This commit is contained in:
parent
3da9e7df5a
commit
0ea88cb6bc
5 changed files with 166 additions and 104 deletions
|
@ -34,6 +34,7 @@ add_executable(
|
||||||
cx
|
cx
|
||||||
src/main.c
|
src/main.c
|
||||||
src/cx.c
|
src/cx.c
|
||||||
|
src/cx_thread.c
|
||||||
src/tensor.c
|
src/tensor.c
|
||||||
src/model.c
|
src/model.c
|
||||||
src/shader.c
|
src/shader.c
|
||||||
|
|
32
include/cx.h
32
include/cx.h
|
@ -19,36 +19,36 @@
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
// Include project headers
|
// Include project headers
|
||||||
|
#include <cx_thread.h>
|
||||||
#include <tensor.h>
|
#include <tensor.h>
|
||||||
#include <model.h>
|
#include <model.h>
|
||||||
#include <tensor.h>
|
#include <tensor.h>
|
||||||
#include <shader.h>
|
|
||||||
#include <neural.h>
|
#include <neural.h>
|
||||||
|
#include <shader.h>
|
||||||
|
|
||||||
// Declare common data structures.
|
// Declare common data structures.
|
||||||
|
|
||||||
typedef struct _cx_thrd {
|
typedef struct _cx_gl_ctx {
|
||||||
pthread_t thread;
|
|
||||||
void *ctx; // Arbitrary thread context
|
|
||||||
} CX_Thread;
|
|
||||||
|
|
||||||
typedef struct _cx_thrgr {
|
|
||||||
CX_Thread *group_manager;
|
|
||||||
CX_Thread **workers;
|
|
||||||
size_t worker_count;
|
|
||||||
size_t worker_size;
|
|
||||||
} CX_ThreadGroup;
|
|
||||||
|
|
||||||
typedef struct _cx_ctx {
|
|
||||||
GLFWwindow *window;
|
GLFWwindow *window;
|
||||||
Neural_Network *nn;
|
ModelRegistry *mr;
|
||||||
CX_ThreadGroup **threads;
|
|
||||||
GLuint *VertexArrayIDs;
|
GLuint *VertexArrayIDs;
|
||||||
size_t VertexArray_count;
|
size_t VertexArray_count;
|
||||||
size_t VertexArray_size;
|
size_t VertexArray_size;
|
||||||
GLuint *programIDs;
|
GLuint *programIDs;
|
||||||
size_t ProgramID_count;
|
size_t ProgramID_count;
|
||||||
size_t ProgramID_size;
|
size_t ProgramID_size;
|
||||||
|
} CX_GL_CTX;
|
||||||
|
|
||||||
|
typedef struct _cx_nn_ctx {
|
||||||
|
Neural_Network *nn;
|
||||||
|
float *input_buffer;
|
||||||
|
float *output_buffer;
|
||||||
|
} CX_NN_CTX;
|
||||||
|
|
||||||
|
typedef struct _cx_ctx {
|
||||||
|
CX_ThreadGroup **threads;
|
||||||
|
CX_GL_CTX *gl_ctx;
|
||||||
|
CX_NN_CTX *nn_ctx;
|
||||||
} CX_Context;
|
} CX_Context;
|
||||||
|
|
||||||
// Declare functions
|
// Declare functions
|
||||||
|
|
19
include/cx_thread.h
Normal file
19
include/cx_thread.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef CX_THREAD_H
|
||||||
|
#define CX_THREAD_H
|
||||||
|
|
||||||
|
typedef struct _cx_thrd {
|
||||||
|
pthread_t thread;
|
||||||
|
void *ctx; // Arbitrary thread context
|
||||||
|
} CX_Thread;
|
||||||
|
|
||||||
|
typedef struct _cx_thrgr {
|
||||||
|
CX_Thread *group_manager;
|
||||||
|
CX_Thread **workers;
|
||||||
|
size_t worker_count;
|
||||||
|
size_t worker_size;
|
||||||
|
} CX_ThreadGroup;
|
||||||
|
|
||||||
|
CX_ThreadGroup *cx_threadGroup_new(void *(*)(void *), void *);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
177
src/cx.c
177
src/cx.c
|
@ -1,41 +1,5 @@
|
||||||
#include <cx.h>
|
#include <cx.h>
|
||||||
|
|
||||||
static CX_Thread *
|
|
||||||
cx_thread_new(void *(*target)(void *),
|
|
||||||
void *ctx) {
|
|
||||||
CX_Thread *self;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
self = malloc(sizeof(CX_Thread));
|
|
||||||
if (!self) {
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
err = pthread_create(&self->thread, NULL, target, ctx);
|
|
||||||
if (err) {
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
self->ctx = ctx;
|
|
||||||
|
|
||||||
err:
|
|
||||||
free(self);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static CX_ThreadGroup *
|
|
||||||
cx_threadGroup_new(void *(*target)(void *),
|
|
||||||
void *ctx) {
|
|
||||||
CX_ThreadGroup *self;
|
|
||||||
|
|
||||||
self = malloc(sizeof(CX_ThreadGroup));
|
|
||||||
|
|
||||||
self->group_manager = cx_thread_new(target, ctx);
|
|
||||||
self->workers = malloc(8 * sizeof(CX_Thread *));
|
|
||||||
self->worker_count = 0;
|
|
||||||
self->worker_size = 8;
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cx_glBindBuffer(GLfloat *render_buffer, GLuint buffer_address,
|
cx_glBindBuffer(GLfloat *render_buffer, GLuint buffer_address,
|
||||||
GLuint gl_index, GLint member_size, GLsizeiptr bufsize) {
|
GLuint gl_index, GLint member_size, GLsizeiptr bufsize) {
|
||||||
|
@ -140,6 +104,7 @@ cx_glinit(GLFWwindow **window) {
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
printf("Window created.\n");
|
||||||
|
|
||||||
glfwMakeContextCurrent(*window);
|
glfwMakeContextCurrent(*window);
|
||||||
|
|
||||||
|
@ -175,46 +140,54 @@ cx_nninit(Neural_Network **nn) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
master_thread(void *ctx) {
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
cx_init(CX_Context **cx_ctx) {
|
cx_init(CX_Context **cx_ctx) {
|
||||||
printf("Initializing CX.");
|
CX_GL_CTX *gl_ctx;
|
||||||
|
CX_NN_CTX *nn_ctx;
|
||||||
|
|
||||||
|
printf("Initializing CX.\n");
|
||||||
|
|
||||||
|
gl_ctx = calloc(1, sizeof(CX_GL_CTX));
|
||||||
|
|
||||||
|
gl_ctx->VertexArrayIDs = calloc(1, sizeof(GLuint));
|
||||||
|
if (!gl_ctx->VertexArrayIDs) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
gl_ctx->VertexArray_count = 0;
|
||||||
|
gl_ctx->VertexArray_size = 1;
|
||||||
|
gl_ctx->programIDs = calloc(1, sizeof(GLuint));
|
||||||
|
if (!gl_ctx->programIDs) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
gl_ctx->ProgramID_count = 0;
|
||||||
|
gl_ctx->ProgramID_size = 1;
|
||||||
|
|
||||||
|
|
||||||
|
// Establish a model registry
|
||||||
|
gl_ctx->mr = modelRegistry_new();
|
||||||
|
|
||||||
|
nn_ctx = calloc(1, sizeof(CX_NN_CTX));
|
||||||
|
|
||||||
*cx_ctx = calloc(1, sizeof(CX_Context));
|
*cx_ctx = calloc(1, sizeof(CX_Context));
|
||||||
(*cx_ctx)->VertexArrayIDs = calloc(1, sizeof(GLuint));
|
|
||||||
if (!(*cx_ctx)->VertexArrayIDs) {
|
(*cx_ctx)->gl_ctx = gl_ctx;
|
||||||
goto err;
|
(*cx_ctx)->nn_ctx = nn_ctx;
|
||||||
}
|
|
||||||
(*cx_ctx)->VertexArray_count = 0;
|
(*cx_ctx)->threads = calloc(1, sizeof(CX_ThreadGroup *));
|
||||||
(*cx_ctx)->VertexArray_size = 1;
|
|
||||||
(*cx_ctx)->programIDs = calloc(1, sizeof(GLuint));
|
|
||||||
if (!(*cx_ctx)->programIDs) {
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
(*cx_ctx)->ProgramID_count = 0;
|
|
||||||
(*cx_ctx)->ProgramID_size = 1;
|
|
||||||
(*cx_ctx)->threads = calloc(1, sizeof(CX_ThreadGroup));
|
|
||||||
if (!(*cx_ctx)->threads) {
|
if (!(*cx_ctx)->threads) {
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cx_glinit(&(*cx_ctx)->window)) {
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cx_nninit(&(*cx_ctx)->nn)) {
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
if (*cx_ctx) {
|
if ((*cx_ctx)->gl_ctx) {
|
||||||
free((*cx_ctx)->VertexArrayIDs);
|
free((*cx_ctx)->gl_ctx->VertexArrayIDs);
|
||||||
free((*cx_ctx)->programIDs);
|
free((*cx_ctx)->gl_ctx->programIDs);
|
||||||
free((*cx_ctx)->threads);
|
free((*cx_ctx)->threads);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,50 +197,78 @@ err:
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
cx_glrun() {
|
cx_glrun(CX_GL_CTX *ctx) {
|
||||||
|
// Remainder from cursor experiments, might be useful later
|
||||||
|
double xpos, ypos;
|
||||||
|
glfwGetCursorPos(ctx->window, &xpos, &ypos);
|
||||||
|
|
||||||
|
do {
|
||||||
|
cx_glrender(ctx->window, ctx->programIDs[0], ctx->mr);
|
||||||
|
usleep(1000000/60);
|
||||||
|
// Check if the ESC key was pressed or the window was closed
|
||||||
|
} while(glfwGetKey(ctx->window, GLFW_KEY_ESCAPE) != GLFW_PRESS
|
||||||
|
&& !glfwWindowShouldClose(ctx->window));
|
||||||
|
|
||||||
|
// Close OpenGL window and terminate GLFW
|
||||||
|
glfwTerminate();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
cx_nnrun(Neural_Network *nn) {
|
cx_nnrun(CX_Thread *self) {
|
||||||
|
|
||||||
// Establish a neural interface.
|
// Establish a neural interface.
|
||||||
float *input_buffer = malloc(64*sizeof(float));
|
|
||||||
float *output_buffer;
|
float *output_buffer;
|
||||||
|
CX_NN_CTX *ctx = self->ctx;
|
||||||
|
|
||||||
output_buffer = neural_process(nn, input_buffer);
|
output_buffer = neural_process(ctx->nn, ctx->input_buffer);
|
||||||
|
|
||||||
|
ctx->output_buffer = output_buffer;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
cx_glthread(void *self) {
|
||||||
|
CX_Thread *self_t = self;
|
||||||
|
CX_GL_CTX *gl_ctx = self_t->ctx;
|
||||||
|
|
||||||
|
cx_glinit(&gl_ctx->window);
|
||||||
|
|
||||||
|
if (cx_loadShaders(gl_ctx->VertexArrayIDs, gl_ctx->programIDs)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cx_glrun(gl_ctx);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
cx_nnthread(void *self) {
|
||||||
|
CX_Thread *self_t = self;
|
||||||
|
CX_NN_CTX *nn_ctx = self_t->ctx;
|
||||||
|
|
||||||
|
cx_nninit(&nn_ctx->nn);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
cx_run(CX_Context *cx_ctx) {
|
cx_run(CX_Context *ctx) {
|
||||||
ModelRegistry *mr;
|
CX_ThreadGroup *tg[2];
|
||||||
|
|
||||||
if (cx_loadShaders(cx_ctx->VertexArrayIDs, cx_ctx->programIDs)) {
|
tg[1] = cx_threadGroup_new(&cx_nnthread, ctx->nn_ctx);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Establish a model registry
|
pthread_join(tg[1]->group_manager->thread, NULL);
|
||||||
mr = modelRegistry_new();
|
|
||||||
// Fill the model registry with mesh models
|
|
||||||
neural_getMesh(cx_ctx->nn, mr);
|
|
||||||
|
|
||||||
// Remainder from cursor experiments, might be useful later
|
neural_getMesh(ctx->nn_ctx->nn, ctx->gl_ctx->mr);
|
||||||
double xpos, ypos;
|
|
||||||
glfwGetCursorPos(cx_ctx->window, &xpos, &ypos);
|
|
||||||
|
|
||||||
|
tg[0] = cx_threadGroup_new(&cx_glthread, ctx->gl_ctx);
|
||||||
|
|
||||||
do {
|
pthread_join(tg[0]->group_manager->thread, NULL);
|
||||||
cx_glrender(cx_ctx->window, cx_ctx->programIDs[0], mr);
|
|
||||||
usleep(1000000/60);
|
|
||||||
// Check if the ESC key was pressed or the window was closed
|
|
||||||
} while(glfwGetKey(cx_ctx->window, GLFW_KEY_ESCAPE) != GLFW_PRESS
|
|
||||||
&& !glfwWindowShouldClose(cx_ctx->window));
|
|
||||||
|
|
||||||
// Close OpenGL window and terminate GLFW
|
modelRegistry_free(ctx->gl_ctx->mr);
|
||||||
glfwTerminate();
|
|
||||||
modelRegistry_free(mr);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
41
src/cx_thread.c
Normal file
41
src/cx_thread.c
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#include <cx.h>
|
||||||
|
|
||||||
|
CX_Thread *
|
||||||
|
cx_thread_new(void *(*target)(void *),
|
||||||
|
void *ctx) {
|
||||||
|
CX_Thread *self;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
self = malloc(sizeof(CX_Thread));
|
||||||
|
if (!self) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
self->ctx = ctx;
|
||||||
|
err = pthread_create(&self->thread, NULL, target, self);
|
||||||
|
if (err) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
|
||||||
|
err:
|
||||||
|
free(self);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CX_ThreadGroup *
|
||||||
|
cx_threadGroup_new(void *(*target)(void *),
|
||||||
|
void *ctx) {
|
||||||
|
CX_ThreadGroup *self;
|
||||||
|
|
||||||
|
self = malloc(sizeof(CX_ThreadGroup));
|
||||||
|
|
||||||
|
self->workers = malloc(8 * sizeof(CX_Thread *));
|
||||||
|
self->worker_count = 0;
|
||||||
|
self->worker_size = 8;
|
||||||
|
|
||||||
|
self->group_manager = cx_thread_new(target, ctx);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue