win_starfield.c (6127B)
1 #include "win_starfield.h" 2 3 internal struct win_starfield_state state; 4 5 int WINAPI 6 WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmdline, int cmdshow) 7 { 8 /* TODO: parse out commandline arguments for debug behaviour? */ 9 (void) instance; 10 (void) prev_instance; 11 (void) cmdline; 12 (void) cmdshow; 13 14 /* NOTE: the windows dll loader checks the parent directory of our 15 * instance when loading libraries, so no need to do anything fancy 16 */ 17 char starfield_library_path[] = "starfield.dll"; 18 19 if (!load_starfield_api(starfield_library_path, &state.starfield_api)) { 20 fprintf(stderr, "Failed to load starfield library: %s\n", starfield_library_path); 21 _exit(1); 22 } 23 24 state.platform_api = load_platform_api(); 25 26 struct starfield_thread thread = { 27 .id = 0, 28 }; 29 30 if (!init_memory(&state.platform_arena, 32 * MiB, 31 &state.renderer_arena, 32 * MiB, 32 &state.starfield_arena, 64 * MiB)) { 33 fprintf(stderr, "Failed to initialise memory\n"); 34 _exit(1); 35 } 36 37 f32 target_render_rate = 60.0, target_physics_rate = 60.0; 38 39 u32 target_us_per_frame = USECS / target_render_rate; 40 u32 target_us_per_tick = USECS / target_physics_rate; 41 42 (void) target_us_per_tick; 43 44 u32 period_us = target_us_per_frame, buffered_periods = 2; 45 if (!init_audio(&state.platform_arena, &state.audio, period_us, buffered_periods)) { 46 fprintf(stderr, "Failed to initialise platform audio\n"); 47 } 48 49 if (!init_video(&state.platform_arena, &state.video, instance)) { 50 fprintf(stderr, "Failed to initialise platform video\n"); 51 _exit(1); 52 } 53 54 if (!init_vulkan(&state.renderer_arena, &state.vulkan)) { 55 fprintf(stderr, "Failed to initialise platform renderer\n"); 56 _exit(1); 57 } 58 59 struct starfield_memory starfield_memory = { 60 .ptr = state.starfield_arena.ptr, 61 .cap = state.starfield_arena.cap, 62 .len = state.starfield_arena.len, 63 }; 64 65 state.starfield_api.init(&thread, &starfield_memory, &state.platform_api); 66 67 state.running = 1; 68 69 f32 dt = 0; 70 while (state.running) { 71 struct starfield_input input = { 72 0, 73 }; 74 75 state.starfield_api.update(&thread, &starfield_memory, 76 &state.platform_api, &input, dt); 77 78 if (state.audio.enabled) { 79 state.starfield_api.sample(&thread, &starfield_memory, 80 &state.platform_api, &state.audio.buffer, dt); 81 82 play_audio(&state.audio); 83 } 84 85 state.starfield_api.render(&thread, &starfield_memory, 86 &state.platform_api, &state.renderer_api, 87 state.video.width, state.video.height, dt); 88 89 draw_frame(&state.video); 90 91 Sleep(1000); 92 } 93 94 state.starfield_api.free(&thread, &state.starfield_memory, &state.platform_api); 95 96 free_vulkan(&state.vulkan); 97 98 _exit(0); 99 } 100 101 #define LOAD_SYMBOL(loc, T, sym) \ 102 ((loc) = (T *) GetProcAddress(library, sym)) 103 104 internal b32 105 load_starfield_api(char const *filename, struct starfield_api *api) 106 { 107 HMODULE library = LoadLibraryA(filename); 108 if (!library) return false; 109 110 LOAD_SYMBOL(api->init, starfield_api_init_t, "starfield_init"); 111 LOAD_SYMBOL(api->update, starfield_api_update_t, "starfield_update"); 112 LOAD_SYMBOL(api->render, starfield_api_render_t, "starfield_render"); 113 LOAD_SYMBOL(api->sample, starfield_api_sample_t, "starfield_sample"); 114 LOAD_SYMBOL(api->free, starfield_api_free_t, "starfield_free"); 115 116 return true; 117 } 118 119 internal b32 120 init_memory(struct arena *platform_arena, u64 platform_capacity, 121 struct arena *renderer_arena, u64 renderer_capacity, 122 struct arena *starfield_arena, u64 starfield_capacity) 123 { 124 #ifdef STARFIELD_DEBUG 125 void *base_addr = (void *) (2 * TiB); 126 #else 127 void *base_addr = NULL; 128 #endif 129 130 u64 huge_page_alignment = GetLargePageMinimum(); 131 u64 len = ALIGN_NEXT(platform_capacity + renderer_capacity + starfield_capacity, 132 huge_page_alignment); 133 134 /* TODO: add hugetlb support? 135 * https://learn.microsoft.com/en-us/windows/win32/memory/large-page-support 136 */ 137 DWORD alloc_type = MEM_RESERVE | MEM_COMMIT; 138 void *ptr = VirtualAlloc(base_addr, len, 139 alloc_type | MEM_LARGE_PAGES, 140 PAGE_READWRITE); 141 142 if (!ptr) 143 ptr = VirtualAlloc(base_addr, len, alloc_type, PAGE_READWRITE); 144 145 if (!ptr) 146 return false; 147 148 /* NOTE: windows guarantees that the memory returned by VirtualAlloc 149 * is zero-ed, so no need to memset it here 150 */ 151 152 platform_arena->ptr = ptr; 153 platform_arena->cap = platform_capacity; 154 platform_arena->len = 0; 155 156 renderer_arena->ptr = (u8 *) ptr + platform_capacity; 157 renderer_arena->cap = renderer_capacity; 158 renderer_arena->len = 0; 159 160 starfield_arena->ptr = (u8 *) ptr + platform_capacity + renderer_capacity; 161 starfield_arena->cap = starfield_capacity; 162 starfield_arena->len = 0; 163 164 return true; 165 } 166 167 internal b32 168 init_audio(struct arena *arena, struct win_audio *audio, u64 period_us, u32 buffered_periods) 169 { 170 (void) arena; 171 (void) audio; 172 (void) period_us; 173 (void) buffered_periods; 174 175 return false; 176 } 177 178 internal void 179 play_audio(struct win_audio *audio) 180 { 181 (void) audio; 182 } 183 184 internal b32 185 init_video(struct arena *arena, struct win_video *video, HINSTANCE instance) 186 { 187 (void) arena; 188 (void) video; 189 (void) instance; 190 191 return false; 192 } 193 194 internal void 195 draw_frame(struct win_video *video) 196 { 197 (void) video; 198 } 199 200 internal b32 201 init_vulkan(struct arena *arena, struct win_vulkan *vulkan) 202 { 203 (void) arena; 204 (void) vulkan; 205 206 return false; 207 } 208 209 internal void 210 free_vulkan(struct win_vulkan *vulkan) 211 { 212 (void) vulkan; 213 } 214 215 /* platform implementation 216 * =========================================================================== 217 */ 218 219 #ifdef STARFIELD_DEBUG 220 221 DEBUG_PLATFORM_READ_FILE(DEBUG_platform_read_file) 222 { 223 (void) filename; 224 225 return (struct DEBUG_platform_read_file_result) {0}; 226 } 227 228 DEBUG_PLATFORM_WRITE_FILE(DEBUG_platform_write_file) 229 { 230 (void) filename; 231 (void) buf; 232 (void) len; 233 234 return false; 235 } 236 237 DEBUG_PLATFORM_FREE_FILE_MEMORY(DEBUG_platform_free_file_memory) 238 { 239 (void) ptr; 240 } 241 242 #endif 243 244 internal struct platform_api 245 load_platform_api(void) 246 { 247 return (struct platform_api) { 248 #ifdef STARFIELD_DEBUG 249 .DEBUG_read_file = DEBUG_platform_read_file, 250 .DEBUG_write_file = DEBUG_platform_write_file, 251 .DEBUG_free_file_memory = DEBUG_platform_free_file_memory, 252 #endif 253 }; 254 } 255 256 /* utils 257 * =========================================================================== 258 */ 259 260 // TODO: implement renderer