1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
#define BUFFER_WIDTH 2048
#define BUFFER_HEIGHT 1024
#define FPS 50
#ifdef _WIN32
#define SLEEP_MARGIN_NS 330000 // 0.33ms (Windows timing functionality is utter garbage)
#else
#define SLEEP_MARGIN_NS 100000 // 0.1ms
#endif
#define ONE_SECOND_NS 1000000000
#define FRAMETIME (ONE_SECOND_NS / FPS)
#define SCREEN_WIDTH 360
#define SCREEN_HEIGHT 270
uint32_t buffer[BUFFER_WIDTH * BUFFER_HEIGHT] __attribute__((section(".bss"), aligned(4096)));
uint32_t display_buffer[SCREEN_WIDTH * SCREEN_HEIGHT] __attribute__((section(".bss"), aligned(4096)));
#ifdef PROFILER
#define MAX_PROFILING_ENTRIES (64)
struct function_cycles {
const char *name;
uint64_t cycles;
uint32_t count;
};
struct debug_state {
struct function_cycles timings[MAX_PROFILING_ENTRIES];
};
#endif
struct state {
// Pointers (8-byte aligned)
uint32_t *display_buffer;
struct { int32_t x, y, w, h; } viewport;
int32_t mouse_dx;
int32_t mouse_dy;
int32_t filter_override; // Manual override: -1 = automatic, 0 = off, 1 = on
float filter_frequency; // Frequency in Hz for squarewave toggle
float contrast;
float saturation;
float brightness;
float tone_data[4];
// OpenGL Objects
GLuint shader_program;
GLuint texture;
GLuint vao;
GLuint vbo;
GLuint ebo;
// Shader Uniforms
GLuint uniform_resolution;
GLuint uniform_src_image_size;
GLuint uniform_brightness;
GLuint uniform_tone;
GLuint uniform_crt_emulation;
GLuint uniform_sampler_location;
GLuint uniform_tex_bounds;
// Rendering & Dynamic Resolution
uint32_t screen_width; // for the debugger
uint32_t screen_height; // for the debugger
uint32_t render_width; // The actual remake resolution (e.g., 360)
uint32_t render_height; // The actual remake resolution (e.g., 270)
uint32_t render_x; // X position inside BUFFER_WIDTH (to track centering)
uint32_t render_y; // Y position inside BUFFER_HEIGHT (to track centering)
uint32_t frame_number;
size_t total_allocated;
bool freewheeling;
bool toggle_crt_emulation;
bool fullscreen;
#ifdef PROFILER
bool overlay;
struct debug_state debug;
#endif
};
struct state state;
static struct remake_callbacks *current_part = 0;
static void render_callback();
static void audio_callback(int16_t *audio_buffer, size_t frames);
static void init_callback();
#ifndef PROFILER
#define PROFILE_NAMED(name)
#define PROFILE_FUNCTION()
#else
struct profiling_context {
uint32_t func_id;
};
__attribute__((section(".bss")))
uint8_t debug_line_buffer[MAX_PROFILING_ENTRIES * 256]; // NOTE(peter): for storing all performance strings in an array to print to the debug-output
__attribute__((always_inline, hot))
static inline uint64_t read_tsc() {
unsigned int aux;
uint64_t result = __rdtscp(&aux);
return result;
}
__attribute__((always_inline, hot))
static inline void end_profiling(struct profiling_context *ctx) __attribute__((unused));
__attribute__((always_inline, hot))
static inline void end_profiling(struct profiling_context *ctx) {
state.debug.timings[ctx->func_id].cycles += read_tsc();
state.debug.timings[ctx->func_id].count++;
}
#define PROFILE_NAMED(name) \
uint32_t func_id = __COUNTER__; \
if((state).debug.timings[func_id].count == 0) \
(state).debug.timings[func_id] = (struct function_cycles){(name), 0, 0}; \
(state).debug.timings[func_id].cycles -= read_tsc(); \
struct profiling_context ctx __attribute__((cleanup(end_profiling))) = { func_id };
#define PROFILE_FUNCTION() \
uint32_t func_id = __COUNTER__; \
if((state).debug.timings[func_id].count == 0) \
(state).debug.timings[func_id] = (struct function_cycles){__func__, 0, 0}; \
(state).debug.timings[func_id].cycles -= read_tsc(); \
struct profiling_context ctx __attribute__((cleanup(end_profiling))) = { func_id };
#endif
|