From 2e976a8d2ea05e97a10fdc30d042bbab7f8d2a77 Mon Sep 17 00:00:00 2001 From: Julia <145168563+julia-aph@users.noreply.github.com> Date: Mon, 29 Apr 2024 15:01:48 -0500 Subject: [PATCH] mm ok --- source/datastructures/ringbuffer.c | 66 ++++++++++++++----- source/datastructures/ringbuffer.h | 27 ++++++-- source/fumotris.c | 2 +- source/fumotris.h | 8 ++- source/io/ctrl.c | 20 +++--- source/io/ctrl.h | 4 +- source/io/input.c | 101 +++++++++++++++++++++-------- source/io/input.h | 18 +++-- source/io/platforms/win.c | 62 +++++++++++------- source/main.c | 19 ++++-- test.exe | Bin 82098 -> 85631 bytes 11 files changed, 231 insertions(+), 96 deletions(-) diff --git a/source/datastructures/ringbuffer.c b/source/datastructures/ringbuffer.c index fb90b00..720e4c7 100644 --- a/source/datastructures/ringbuffer.c +++ b/source/datastructures/ringbuffer.c @@ -1,35 +1,67 @@ -#pragma once #include "ringbuffer.h" #include -struct rbuf_generic { +struct ring_buf { struct RingBufferHead head; - u8 arr[]; + u8 bytes[]; }; -inline void *rbuf_start(RingBufferT T, struct rbuf_generic *rbuf, size_t i) +void *get_ptr(RingBufferT T, struct RingBufferHead *head, size_t i) { - size_t wrap_i = (rbuf->head.start + i) % T->LEN; - return rbuf->arr + wrap_i * T->SIZE; + struct ring_buf *ring = (struct ring_buf *)head; + return ring->bytes + T->SIZE * i; } -inline void *rbuf_tail(RingBufferT T, struct rbuf_generic *rbuf, size_t i) +size_t RingBufferEmpty(RingBufferT T, struct RingBufferHead *head) { - size_t wrap_i = (rbuf->head.start + rbuf->head.len + i) % T->LEN; - return rbuf->arr + i * T->SIZE; + return T->LEN - head->len; } -void RingBufferTransfer(RingBufferT T, RingBuffer *dest, RingBuffer *tmp) -{ - struct rbuf_generic *write = dest; - struct rbuf_generic *read = tmp; +void *RingBufferGet(RingBufferT T, struct RingBufferHead *head, size_t i) +{ + size_t wrap_i = (head->start + i) % T->LEN; + return get_ptr(T, head, wrap_i); +} - size_t copy_max = min_size(T->LEN - write->head.len, read->head.len); +void *RingBufferNext(RingBufferT T, struct RingBufferHead *head) +{ + size_t wrap_i = (head->start + head->len) % T->LEN; + return get_ptr(T, head, wrap_i); +} + +void RingBufferAdd(RingBufferT T, struct RingBufferHead *dest, void *item) +{ + memcpy(RingBufferNext(T, dest), item, T->SIZE); +} + +void RingBufferTransfer( + RingBufferT T, + struct RingBufferHead *dest, + struct RingBufferHead *src +) { + size_t copy_max = min_size(T->LEN - dest->len, src->len); for (size_t i = 0; i < copy_max; i++) { - memcpy(rbuf_tail(T, write, i), rbuf_start(T, read, i), T->LEN); + void *to = RingBufferGet(T, dest_head, dest->len + i); + void *from = RingBufferGet(T, src_head, i); + memcpy(to, from, T->SIZE); } - write->head.start += copy_max; - read->head.len -= copy_max; + dest->len += copy_max; + src->len -= copy_max; +} + +size_t RingBufferOut(RingBufferT T, size_t n, void *dest, void *src_head) +{ + struct ring_buf *src = src_head; + + size_t copy_max = min_size(n, src->head.len); + + for (size_t i = 0; i < copy_max; i++) { + void *to = (char *)dest + i * T->SIZE; + void *from = RingBufferGet(T, src, i); + memcpy(to, from, T->SIZE); + } + + return copy_max; } \ No newline at end of file diff --git a/source/datastructures/ringbuffer.h b/source/datastructures/ringbuffer.h index 6f5af8c..8038491 100644 --- a/source/datastructures/ringbuffer.h +++ b/source/datastructures/ringbuffer.h @@ -7,8 +7,6 @@ #include "fumotris.h" -typedef void *RingBuffer; - typedef const struct RingBufferT { size_t LEN; size_t SIZE; @@ -19,6 +17,27 @@ struct RingBufferHead { u8f start; }; -void RingBufferTransfer(RingBufferT T, RingBuffer *dest, RingBuffer *tmp); +#define RINGBUF_HEAD_INIT ((struct RingBufferHead) { 0, 0 }) -#define INIT_RING_BUF_T(len, type) &(struct RingBufferT) { len, sizeof(type) } \ No newline at end of file +size_t RingBufferEmpty(RingBufferT T, struct RingBufferHead *head); + +void *RingBufferGet( + RingBufferT T, + struct RingBufferHead *head, + size_t i +); + +void *RingBufferNext(RingBufferT T, struct RingBufferHead *head); + +void RingBufferTransfer( + RingBufferT T, + struct RingBufferHead *dest, + struct RingBufferHead *tmp +); + +size_t RingBufferOut( + RingBufferT T, + size_t n, + void *dest, + struct RingBufferHead *src +); \ No newline at end of file diff --git a/source/fumotris.c b/source/fumotris.c index d81b99a..ac5853f 100644 --- a/source/fumotris.c +++ b/source/fumotris.c @@ -1,6 +1,6 @@ #include "fumotris.h" -inline size_t min_size(size_t a, size_t b) +size_t min_size(size_t a, size_t b) { return a < b ? a : b; } \ No newline at end of file diff --git a/source/fumotris.h b/source/fumotris.h index d7488a6..4fb5281 100644 --- a/source/fumotris.h +++ b/source/fumotris.h @@ -1,7 +1,9 @@ #pragma once +#include #include -#define nullptr ((void*)0) +#define nullptr ((void *)0) + typedef uint8_t u8; typedef uint_fast8_t u8f; @@ -28,7 +30,9 @@ typedef int_fast32_t i32f; typedef int64_t i64; typedef int_fast64_t i64f; -inline size_t min_size(size_t a, size_t b); + +size_t min_size(size_t a, size_t b); + /*const u8 I[16] = { 0, 0, 0, 0, diff --git a/source/io/ctrl.c b/source/io/ctrl.c index f2b283d..2fda0ef 100644 --- a/source/io/ctrl.c +++ b/source/io/ctrl.c @@ -1,5 +1,7 @@ #include "ctrl.h" +#include "ringbuffer.h" + #define INIT_SIZE 16 bool CreateCtrl(struct Controller *ctrl) @@ -12,7 +14,7 @@ bool CreateCtrl(struct Controller *ctrl) return false; *ctrl = (struct Controller) { - .recs.len = 0, + .recs.head = RINGBUF_HEAD_INIT, .pending_buf.len = 0, .axis_vec = (struct ctrl_axis_vec) { @@ -49,7 +51,7 @@ size_t wrap_index(size_t i, size_t max) { return i % (SIZE_MAX - max + 1); } -struct ctrl_bkt *find_or_set(struct ctrl_dict *dict, union InputID id) +struct ctrl_bkt *find_set(struct ctrl_dict *dict, union InputID id) { size_t i = id.hash % dict->capacity; @@ -99,14 +101,14 @@ struct InputAxis *find_axis(struct ctrl_dict *dict, union InputID id) return bkt->axis; } -union InputID to_id(u16f value, u16f type) { +union InputID as_id(u16f value, u16f type) { return (union InputID) { .value = value, .type = type }; } bool CtrlMap(struct Controller *ctrl, u16f code, u16f type, u16f bind) { - struct ctrl_bkt *code_bkt = find_or_set(&ctrl->codes, to_id(code, type)); - struct ctrl_bkt *bind_bkt = find_or_set(&ctrl->binds, to_id(bind, type)); + struct ctrl_bkt *code_bkt = find_set(&ctrl->codes, as_id(code, type)); + struct ctrl_bkt *bind_bkt = find_set(&ctrl->binds, as_id(bind, type)); if (code_bkt->axis == nullptr) code_bkt->axis = &ctrl->axis_vec.axes[ctrl->axis_vec.len++]; @@ -120,7 +122,7 @@ bool CtrlMap(struct Controller *ctrl, u16f code, u16f type, u16f bind) struct InputAxis *CtrlGet(struct Controller *ctrl, u16f code, u16f type) { - struct ctrl_bkt *code_bkt = find(&ctrl->codes, to_id(code, type)); + struct ctrl_bkt *code_bkt = find(&ctrl->codes, as_id(code, type)); if (code_bkt == nullptr) return nullptr; @@ -152,7 +154,7 @@ void CtrlPoll(struct Controller *ctrl) } ctrl->pending_buf.len = 0; - for (size_t i = 0; i < ctrl->recs.len; i++) { + for (size_t i = 0; i < ctrl->recs.head.len; i++) { struct InputRecord *rec = &ctrl->recs.buf[i]; struct InputAxis *axis = find_axis(&ctrl->binds, rec->id); @@ -164,12 +166,12 @@ void CtrlPoll(struct Controller *ctrl) ctrl->pending_buf.axes[ctrl->pending_buf.len++] = axis; } - ctrl->recs.len = 0; + ctrl->recs.head.len = 0; } size_t CtrlInputString(struct Controller *ctrl, size_t n, char *buf) { - size_t copy_max = min_size(ctrl->str.len, n); + return RingBufferOut(&STR_BUF_T, n, buf, &ctrl->str.head); } /*int main() diff --git a/source/io/ctrl.h b/source/io/ctrl.h index e64d4e8..875475a 100644 --- a/source/io/ctrl.h +++ b/source/io/ctrl.h @@ -68,7 +68,9 @@ bool CtrlMap(struct Controller *ctrl, u16f code, u16f type, u16f bind); struct InputAxis *CtrlGet(struct Controller *ctrl, u16f code, u16f type); -bool CtrlPoll(struct Controller *ctrl, struct InputThreadHandle *hand); +void CtrlPoll(struct Controller *ctrl); + +size_t CtrlInputString(struct Controller *ctrl, size_t n, char *buf); enum ControlCode { LEFT, diff --git a/source/io/input.c b/source/io/input.c index ffd3223..a1c5300 100644 --- a/source/io/input.c +++ b/source/io/input.c @@ -3,65 +3,114 @@ #include "platform.h" -void *input_thread_loop(void *arg) -{ - struct InputThreadHandle *hand = arg; +const struct RingBufferT IO_BUF_T = { + .LEN = IO_BUF_SIZE, + .SIZE = sizeof(struct InputRecord) +}; - struct InputRecordBuf tmp_in = { .head.len = 0, .head.start = 0 }; +const struct RingBufferT STR_BUF_T = { + .LEN = STR_BUF_SIZE, + .SIZE = sizeof(char) +}; + +void *input_worker(void *arg) +{ + struct InputHandle *hand = arg; + + struct InputRecordBuf tmp_recs = { .head.len = 0, .head.start = 0 }; struct InputStringBuf tmp_str = { .head.len = 0, .head.start = 0 }; while (!hand->is_terminating) { - if (!PlatformReadInput(&tmp_in, &tmp_str)) + if (!PlatformReadInput(&tmp_recs, &tmp_str)) { + hand->err = true; return nullptr; + } + printf("input read, len:%u\n", hand->recs->head.len); - if (hand->err = pthread_mutex_lock(&hand->mutex)) - return nullptr; - - while (tmp_in.head.len == IO_BUF_SIZE) { - if (hand->err = pthread_cond_wait(&hand->consume, &hand->mutex)) - return nullptr; + for (int i = 0; i < hand->recs->head.len; i++) { + struct InputRecord *rec = RingBufferGet(&IO_BUF_T, &hand->recs->head, i); + printf("\ti:%u, type:%u, but:%u\n", i, rec->id.type, rec->id.bind); } - RingBufferTransfer(IO_BUF_T, hand->in, &tmp_in); - RingBufferTransfer(STR_BUF_T, hand->str, &tmp_str); - - if (hand->err = pthread_mutex_unlock(&hand->mutex)) + if (pthread_mutex_lock(&hand->mutex) != 0) { + hand->err = true; return nullptr; + } + + while (tmp_recs.head.len == IO_BUF_SIZE) { + if (pthread_cond_wait(&hand->is_consumed, &hand->mutex) != 0) { + hand->err = true; + return nullptr; + } + } + + RingBufferTransfer(&IO_BUF_T, &hand->recs->head, &tmp_recs.head); + RingBufferTransfer(&STR_BUF_T, &hand->str->head, &tmp_str.head); + + if (pthread_mutex_unlock(&hand->mutex) != 0) { + hand->err = true; + return nullptr; + } } return nullptr; } bool BeginInputThread( - struct InputThreadHandle *hand, + struct InputHandle *hand, struct InputRecordBuf *in, struct InputStringBuf *str ) { - *hand = (struct InputThreadHandle) { - .in = in, + *hand = (struct InputHandle) { + .recs = in, .str = str, - - .mutex = PTHREAD_MUTEX_INITIALIZER, - .consume = PTHREAD_COND_INITIALIZER, - + .err = 0, .is_terminating = false, }; - return pthread_create(&hand->thread, nullptr, input_thread_loop, hand) == 0; + if (pthread_mutex_init(&hand->mutex, nullptr) != 0) + return false; + + if (pthread_cond_init(&hand->is_consumed, nullptr) != 0) + return false; + + if (pthread_create(&hand->thread, nullptr, input_worker, hand) != 0) + return false; + + return true; } -bool EndInputThread(struct InputThreadHandle *hand) +bool EndInputThread(struct InputHandle *hand) { hand->is_terminating = true; if (!PlatformStopInput()) return false; - if (!pthread_mutex_destroy(&hand->mutex)) + if (pthread_mutex_destroy(&hand->mutex) != 0) return false; - if (!pthread_join(hand->thread, nullptr)) + if (pthread_join(hand->thread, nullptr) != 0) + return false; + + return true; +} + +bool InputAquire(struct InputHandle *hand) +{ + if (pthread_mutex_lock(&hand->mutex) != 0) + return false; + + return true; +} + +bool InputRelease(struct InputHandle *hand) +{ + if (pthread_cond_signal(&hand->is_consumed) != 0) + return false; + + if (pthread_mutex_unlock(&hand->mutex) != 0) return false; return true; diff --git a/source/io/input.h b/source/io/input.h index 9869bec..d21d391 100644 --- a/source/io/input.h +++ b/source/io/input.h @@ -68,8 +68,8 @@ struct InputRecord { }; }; -RingBufferT IO_BUF_T = INIT_RING_BUF_T(IO_BUF_SIZE, struct InputRecord); -RingBufferT STR_BUF_T = INIT_RING_BUF_T(STR_BUF_SIZE, char); +extern const struct RingBufferT IO_BUF_T; +extern const struct RingBufferT STR_BUF_T; struct InputRecordBuf { struct RingBufferHead head; @@ -81,22 +81,26 @@ struct InputStringBuf { char buf[STR_BUF_SIZE]; }; -struct InputThreadHandle { - struct InputRecordBuf *in; +struct InputHandle { + struct InputRecordBuf *recs; struct InputStringBuf *str; pthread_t thread; pthread_mutex_t mutex; - pthread_cond_t consume; + pthread_cond_t is_consumed; int err; bool is_terminating; }; bool BeginInputThread( - struct InputThreadHandle *hand, + struct InputHandle *hand, struct InputRecordBuf *in, struct InputStringBuf *str ); -bool EndInputThread(struct InputThreadHandle *hand); \ No newline at end of file +bool EndInputThread(struct InputHandle *hand); + +bool InputAquire(struct InputHandle *hand); + +bool InputRelease(struct InputHandle *hand); \ No newline at end of file diff --git a/source/io/platforms/win.c b/source/io/platforms/win.c index aa0b62f..3f78519 100644 --- a/source/io/platforms/win.c +++ b/source/io/platforms/win.c @@ -5,6 +5,7 @@ #include "gametime.h" #include "input.h" #include "parseinput.h" +#include "ringbuffer.h" #define MOUSE_MOVE (MOUSE_EVENT | MOUSE_MOVED) #define MOUSE_VWHEEL (MOUSE_EVENT | MOUSE_WHEELED) @@ -71,6 +72,11 @@ struct win_rec { }; }; +union record { + struct win_rec native; + INPUT_RECORD win; +}; + bool init_handles() { win.input_hand = GetStdHandle(STD_INPUT_HANDLE); @@ -127,46 +133,56 @@ bool dispatch_rec( u8f type = rec->type | (rec->is_mouse & rec->mouse.flags); switch (type) { - case KEY_EVENT: - ReadButton(out, rec->key.vk_code, rec->key.is_down); - str->len += UCS2ToUTF8(&str->buf[str->len], rec->key.ucs2_char); - return true; + case KEY_EVENT: { + ReadButton(out, rec->key.vk_code, rec->key.is_down); - case MOUSE_MOVE: - ReadJoystick(out, 0, rec->mouse.pos.x, rec->mouse.pos.y); - return true; + char *to = RingBufferGet(&STR_BUF_T, &str->head, str->head.len); + str->head.len += UCS2ToUTF8(to, rec->key.ucs2_char); - case MOUSE_VWHEEL: - case MOUSE_HWHEEL: - ReadAxis(out, rec->mouse.is_hwheel, rec->mouse.but); - return true; - - case WINDOW_BUFFER_SIZE_EVENT: - return false; - // TODO: Handle window resizing + return true; + } + case MOUSE_MOVE: { + ReadJoystick(out, 0, rec->mouse.pos.x, rec->mouse.pos.y); + + return true; + } + case MOUSE_VWHEEL: { + ReadAxis(out, 0, rec->mouse.but); + + return true; + } + case MOUSE_HWHEEL: { + ReadAxis(out, 1, rec->mouse.but); + + return true; + } + case WINDOW_BUFFER_SIZE_EVENT: { + // TODO: Handle window resizing + + return false; + } } return false; } -bool PlatformReadInput(struct InputRecordBuf *in, struct InputStringBuf *str) +bool PlatformReadInput(struct InputRecordBuf *recs, struct InputStringBuf *str) { - DWORD max_records = IO_BUF_SIZE - in->len; - struct win_rec win_buf[max_records]; + DWORD read_max = RingBufferEmpty(&IO_BUF_T, &recs->head); + union record win_buf[read_max]; DWORD filled; - if (!ReadConsoleInputW(win.input_hand, win_buf, max_records, &filled)) + if (!ReadConsoleInputW(win.input_hand, &win_buf->win, read_max, &filled)) return false; Time now = TimeNow(); for (size_t i = 0; i < filled; i++) { - size_t rec_i = (in->start + in->len) % IO_BUF_SIZE; - struct InputRecord *rec = &in->buf[rec_i]; + struct InputRecord *rec = RingBufferNext(&IO_BUF_T, &recs->head); - if (dispatch_rec(rec, str, win_buf + i)) { + if (dispatch_rec(rec, str, &win_buf->native + i)) { rec->time = now; - in->len += 1; + recs->head.len += 1; } } diff --git a/source/main.c b/source/main.c index 9767d58..359551a 100644 --- a/source/main.c +++ b/source/main.c @@ -36,20 +36,27 @@ int main() if (!CreateCtrl(&ctrl)) ErrorExit("Out of memory"); + CtrlMap(&ctrl, 0, BUTTON, 'A'); + struct Game game; CreateEvent(&game.Update); - struct InputThreadHandle input_hand; + struct InputHandle input_hand; if (!BeginInputThread(&input_hand, &ctrl.recs, &ctrl.str)) ErrorExit("Input handle failed to initialize"); - CtrlMap(&ctrl, 0, BUTTON, 'A'); - + _sleep(1000000); while (true) { - if(!CtrlPoll(&ctrl, &input_hand)) - ErrorExit("Poll failed"); + if (!InputAquire(&input_hand)) + ErrorExit("Aquire failed"); + + //printf("%u\n", ctrl.recs.head.len); + //CtrlPoll(&ctrl); - EventInvokeUpdate(&game.Update, nullptr); + if (!InputRelease(&input_hand)) + ErrorExit("Release failed"); + + EventInvokeUpdate(&game.Update, 0); } return 0; diff --git a/test.exe b/test.exe index 0c466d47bde780d73be10102387ba15f951637b7..978fa636adcfa5922497446d53a9cb18da00d021 100644 GIT binary patch delta 25256 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 AasU7T delta 22358 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 gF^Bg~6#I5^zcm%ijw#|Pw{NQW$l;1