main_w32.c (4976B)
1 /* See LICENSE for license details. */ 2 #ifndef _WIN32 3 #error This file is only meant to be compiled for Win32 4 #endif 5 6 #include "beamformer.h" 7 8 typedef struct { 9 iptr io_completion_handle; 10 } w32_context; 11 12 enum w32_io_events { 13 W32_IO_FILE_WATCH, 14 W32_IO_PIPE, 15 }; 16 17 typedef struct { 18 u64 tag; 19 iptr context; 20 } w32_io_completion_event; 21 22 #include "os_win32.c" 23 24 #define OS_DEBUG_LIB_NAME ".\\beamformer.dll" 25 #define OS_DEBUG_LIB_TEMP_NAME ".\\beamformer_temp.dll" 26 27 #define OS_CUDA_LIB_NAME "external\\cuda_toolkit.dll" 28 #define OS_CUDA_LIB_TEMP_NAME "external\\cuda_toolkit_temp.dll" 29 30 #define OS_RENDERDOC_SONAME "renderdoc.dll" 31 32 #define OS_PIPE_NAME "\\\\.\\pipe\\beamformer_data_fifo" 33 #define OS_SMEM_NAME "Local\\ogl_beamformer_parameters" 34 35 #define OS_PATH_SEPERATOR "\\" 36 37 #include "static.c" 38 39 static void 40 dispatch_file_watch(OS *os, FileWatchDirectory *fw_dir, u8 *buf, Arena arena) 41 { 42 i64 offset = 0; 43 TempArena save_point = {0}; 44 w32_file_notify_info *fni = (w32_file_notify_info *)buf; 45 do { 46 end_temp_arena(save_point); 47 save_point = begin_temp_arena(&arena); 48 49 Stream path = {.data = arena_commit(&arena, KB(1)), .cap = KB(1)}; 50 51 if (fni->action != FILE_ACTION_MODIFIED) { 52 stream_append_s8(&path, s8("unknown file watch event: ")); 53 stream_append_u64(&path, fni->action); 54 stream_append_byte(&path, '\n'); 55 os->write_file(os->stderr, stream_to_s8(&path)); 56 stream_reset(&path, 0); 57 } 58 59 stream_append_s8(&path, fw_dir->name); 60 stream_append_byte(&path, '\\'); 61 62 s8 file_name = s16_to_s8(&arena, (s16){.data = fni->filename, 63 .len = fni->filename_size / 2}); 64 stream_append_s8(&path, file_name); 65 stream_append_byte(&path, 0); 66 stream_commit(&path, -1); 67 68 u64 hash = s8_hash(file_name); 69 for (u32 i = 0; i < fw_dir->file_watch_count; i++) { 70 FileWatch *fw = fw_dir->file_watches + i; 71 if (fw->hash == hash) { 72 fw->callback(os, stream_to_s8(&path), fw->user_data, arena); 73 break; 74 } 75 } 76 77 offset = fni->next_entry_offset; 78 fni = (w32_file_notify_info *)((u8 *)fni + offset); 79 } while (offset); 80 } 81 82 static void 83 clear_io_queue(OS *os, BeamformerInput *input, Arena arena) 84 { 85 w32_context *ctx = (w32_context *)os->context; 86 87 iptr handle = ctx->io_completion_handle; 88 w32_overlapped *overlapped; 89 u32 bytes_read; 90 uptr user_data; 91 while (GetQueuedCompletionStatus(handle, &bytes_read, &user_data, &overlapped, 0)) { 92 w32_io_completion_event *event = (w32_io_completion_event *)user_data; 93 switch (event->tag) { 94 case W32_IO_FILE_WATCH: { 95 FileWatchDirectory *dir = (FileWatchDirectory *)event->context; 96 dispatch_file_watch(os, dir, dir->buffer.beg, arena); 97 zero_struct(overlapped); 98 ReadDirectoryChangesW(dir->handle, dir->buffer.beg, 4096, 0, 99 FILE_NOTIFY_CHANGE_LAST_WRITE, 0, overlapped, 0); 100 } break; 101 case W32_IO_PIPE: break; 102 } 103 } 104 } 105 106 static b32 107 poll_pipe(Pipe *p, Stream *e, OS *os) 108 { 109 u8 data; 110 i32 total_read = 0; 111 b32 result = ReadFile(p->file, &data, 0, &total_read, 0); 112 if (!result) { 113 i32 error = GetLastError(); 114 /* NOTE: These errors mean nothing's been sent yet, otherwise pipe is busted 115 * and needs to be recreated. */ 116 if (error != ERROR_NO_DATA && 117 error != ERROR_PIPE_LISTENING && 118 error != ERROR_PIPE_NOT_CONNECTED) 119 { 120 DisconnectNamedPipe(p->file); 121 CloseHandle(p->file); 122 *p = os_open_named_pipe(p->name); 123 124 if (p->file == INVALID_FILE) { 125 stream_append_s8(e, s8("poll_pipe: failed to reopen pipe: error: ")); 126 stream_append_i64(e, GetLastError()); 127 stream_append_byte(e, '\n'); 128 os->write_file(os->stderr, stream_to_s8(e)); 129 stream_reset(e, 0); 130 } 131 } 132 } 133 return result; 134 } 135 136 int 137 main(void) 138 { 139 BeamformerCtx ctx = {0}; 140 BeamformerInput input = {.executable_reloaded = 1}; 141 Arena temp_memory = os_alloc_arena((Arena){0}, MB(16)); 142 ctx.error_stream = stream_alloc(&temp_memory, MB(1)); 143 144 ctx.ui_backing_store = sub_arena(&temp_memory, MB(2), KB(4)); 145 ctx.os.compute_worker.arena = sub_arena(&temp_memory, MB(2), KB(4)); 146 147 Pipe data_pipe = os_open_named_pipe(OS_PIPE_NAME); 148 input.pipe_handle = data_pipe.file; 149 ASSERT(data_pipe.file != INVALID_FILE); 150 151 #define X(name) ctx.os.name = os_ ## name; 152 OS_FNS 153 #undef X 154 155 w32_context w32_ctx = {0}; 156 w32_ctx.io_completion_handle = CreateIoCompletionPort(INVALID_FILE, 0, 0, 0); 157 158 ctx.os.context = (iptr)&w32_ctx; 159 ctx.os.compute_worker.asleep = 1; 160 ctx.os.stderr = GetStdHandle(STD_ERROR_HANDLE); 161 162 debug_init(&ctx.os, (iptr)&input, &temp_memory); 163 setup_beamformer(&ctx, &temp_memory); 164 os_wake_thread(ctx.os.compute_worker.sync_handle); 165 166 while (!ctx.should_exit) { 167 clear_io_queue(&ctx.os, &input, temp_memory); 168 169 input.last_mouse = input.mouse; 170 input.mouse.rl = GetMousePosition(); 171 172 input.pipe_data_available = poll_pipe(&data_pipe, &ctx.error_stream, &ctx.os); 173 174 beamformer_frame_step(&ctx, &temp_memory, &input); 175 176 input.executable_reloaded = 0; 177 } 178 }