summaryrefslogtreecommitdiff
path: root/base/state.c
blob: 1e9d95b4d35496d15e4aae79767f216c6e6ad73e (plain)
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
135

#define BUFFER_WIDTH  256		// render buffer
#define BUFFER_HEIGHT 240		// render buffer
#define FPS 60.1
#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 256	// screen size
#define SCREEN_HEIGHT 240	// screen size

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();
static void shutdown_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