diff --git a/Makefile b/Makefile index f746c7d..07b180c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ CC := gcc CFLAGS := -Wall -Wextra -g -fsanitize=address,undefined $(shell sdl2-config --cflags) -CFLAGS += -O3 -march=native +CFLAGS += -O3 -march=native -fopt-info-optimized +#CFLAGS += -fsanitize=address LDFLAGS := $(shell sdl2-config --libs) TARGET := game_of_life diff --git a/src/game_core.c b/src/game_core.c index de4b9fa..ca05e12 100644 --- a/src/game_core.c +++ b/src/game_core.c @@ -1,4 +1,6 @@ #include "game_core.h" +#include +#include #include const int directions[8][2] = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, @@ -73,3 +75,57 @@ Board process_game(Board board) { board.pixels = tmp; return board; } + +void* process_chunk(void* arg) { + ThreadArgs* ta = (ThreadArgs*)arg; + Board board = (*ta[0].board); + size_t x, y; + uint8_t count = 0; + for (y = ta->y_start; y < ta->y_end; y++) { + for (x = 0; x < board.width; x++) { + count = count_adjacent(board, x, y); + if (board.pixels[y * board.width + x] == BLACK && count == 3) { + board.next_pixels[y * board.width + x] = WHITE; + } else if (board.pixels[y * board.width + x] == WHITE && + count != 2 && count != 3) { + board.next_pixels[y * board.width + x] = BLACK; + } else { + board.next_pixels[y * board.width + x] = + board.pixels[y * board.width + x]; + } + } + } + return NULL; +} + +ThreadArgs* make_chunk(Board* board, size_t n_threads) { + size_t i; + size_t chunk = board->height / n_threads; + ThreadArgs* output = malloc(sizeof(ThreadArgs) * n_threads); + for (i = 0; i < n_threads; i++) { + output[i].board = board; + output[i].y_start = i * chunk; + output[i].y_end = + (i == n_threads - 1) ? board->height : (i + 1) * chunk; + } + return output; +} + +Board process_game_mt(ThreadArgs* ta, + Board board, + pthread_t* threads, + size_t n_threads) { + size_t i = 0; + + for (i = 0; i < n_threads; i++) { + ta[i].board = &board; + pthread_create(&threads[i], NULL, process_chunk, &ta[i]); + } + for (i = 0; i < n_threads; i++) { + pthread_join(threads[i], NULL); + } + uint32_t* tmp = board.next_pixels; + board.next_pixels = board.pixels; + board.pixels = tmp; + return board; +} diff --git a/src/game_core.h b/src/game_core.h index ff6c3bf..e7818ba 100644 --- a/src/game_core.h +++ b/src/game_core.h @@ -14,10 +14,22 @@ typedef struct { size_t height; } Board; +typedef struct { + Board* board; + size_t y_start; + size_t y_end; +} ThreadArgs; + void free_board(Board board); Board init_board(size_t width, size_t height, int random); int count_adjacent(Board board, size_t x, size_t y); +ThreadArgs* make_chunk(Board* board, size_t n_threads); Board process_game(Board board); +Board process_game_mt(ThreadArgs* ta, + Board board, + pthread_t* threads, + size_t n_threads); void display_board(Board board); +void* process_chunk(void* ta); #endif diff --git a/src/main.c b/src/main.c index b629526..c7fd90f 100644 --- a/src/main.c +++ b/src/main.c @@ -1,17 +1,24 @@ #include +#include #include +#include +#include #include #include #include #include +#include #include "game_core.h" #include "utils.h" #define SEED (5) #define WIDTH (800) #define HEIGHT (600) -#define SIM_WIDTH (800) -#define SIM_HEIGHT (600) +#define SIM_WIDTH (80) +#define SIM_HEIGHT (60) + +const int FPS = 15; +const int FRAME_DELAY = 1000 / FPS; t_flags process_args(int argc, char** argv) { t_flags output_flags = {0}; @@ -36,54 +43,83 @@ t_flags process_args(int argc, char** argv) { } int main(int argc, char* argv[]) { + pthread_t* threads; + int n_threads = sysconf(_SC_NPROCESSORS_ONLN); + size_t n_chunk; + ThreadArgs* ta; t_flags flags = process_args(argc, argv); + printf("G : %d , M : %d (n : %d)\n", flags.graphical, flags.multithread, + n_threads); srand(time(NULL)); if (flags.graphical) { - Board b = init_board(SIM_WIDTH, SIM_HEIGHT, 0); + Board b = init_board(SIM_WIDTH, SIM_HEIGHT, 1); b.pixels[0 * SIM_WIDTH + 1] = WHITE; b.pixels[1 * SIM_WIDTH + 2] = WHITE; b.pixels[2 * SIM_WIDTH + 0] = WHITE; b.pixels[2 * SIM_WIDTH + 1] = WHITE; b.pixels[2 * SIM_WIDTH + 2] = WHITE; + if (flags.multithread) { + ta = make_chunk(&b, (int)n_threads); + threads = malloc(sizeof(pthread_t) * n_threads); + n_chunk = b.height / n_threads; + } + // SDL2 SDL_Init(SDL_INIT_VIDEO); - SDL_Window* win = SDL_CreateWindow("pixels", 0, 0, WIDTH, HEIGHT, 0); SDL_Renderer* ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED); - SDL_Texture* tex = SDL_CreateTexture(ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, SIM_WIDTH, SIM_HEIGHT); - - int running = 1; SDL_Event e; int pitch; void* tex_pixels; + + // While running frames + int running = 1; + int paused = 0; + int next_frame = 0; + Uint32 frame_start; + Uint32 frame_time; + SDL_Rect dst = {0, 0, WIDTH, HEIGHT}; while (running) { - while (SDL_PollEvent(&e)) + frame_start = SDL_GetTicks(); + if (next_frame) + next_frame = 0; + while (SDL_PollEvent(&e)) { if (e.type == SDL_QUIT) running = 0; + if (e.type == SDL_KEYDOWN) { + if (e.key.keysym.sym == SDLK_SPACE) + paused = !paused; + if (e.key.keysym.sym == SDLK_RIGHT) + next_frame = 1; + } + } - SDL_Rect dst = {0, 0, WIDTH, HEIGHT}; - SDL_LockTexture(tex, NULL, &tex_pixels, &pitch); - memcpy(tex_pixels, b.pixels, - SIM_WIDTH * SIM_HEIGHT * sizeof(uint32_t)); - SDL_UnlockTexture(tex); - // SDL_UpdateTexture(tex, NULL, b.pixels,SIM_WIDTH * - // sizeof(uint32_t)); - // SDL_RenderClear(ren); - SDL_RenderCopy(ren, tex, NULL, &dst); - SDL_RenderPresent(ren); - b = process_game(b); - // SDL_Delay(100); + if (!paused || next_frame) { + SDL_LockTexture(tex, NULL, &tex_pixels, &pitch); + memcpy(tex_pixels, b.pixels, + SIM_WIDTH * SIM_HEIGHT * sizeof(uint32_t)); + SDL_UnlockTexture(tex); + SDL_RenderCopy(ren, tex, NULL, &dst); + SDL_RenderPresent(ren); + b = !flags.multithread + ? process_game(b) + : process_game_mt(ta, b, threads, n_threads); + } + frame_time = SDL_GetTicks() - frame_start; + if (frame_time < FRAME_DELAY) + SDL_Delay(FRAME_DELAY - frame_time); } SDL_DestroyTexture(tex); SDL_DestroyRenderer(ren); SDL_DestroyWindow(win); SDL_Quit(); free_board(b); + free(threads); } else { Board b = init_board(SIM_WIDTH, SIM_HEIGHT, 1);