aboutsummaryrefslogtreecommitdiff
path: root/patches/mame2000/0002-add-frameskip.patch
blob: a07582e779ed1d9da2e9d27c709c0f793799e359 (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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
diff --git a/src/libretro/libretro.c b/src/libretro/libretro.c
index 521a561..514e335 100644
--- a/src/libretro/libretro.c
+++ b/src/libretro/libretro.c
@@ -51,6 +51,20 @@ static scond_t   *libretro_cond = NULL;
 static slock_t   *libretro_mutex = NULL;
 #endif
 
+unsigned frameskip_type                  = 0;
+unsigned frameskip_threshold             = 0;
+unsigned frameskip_counter               = 0;
+unsigned frameskip_interval              = 0;
+
+int retro_audio_buff_active              = false;
+unsigned retro_audio_buff_occupancy      = 0;
+int retro_audio_buff_underrun            = false;
+
+unsigned retro_audio_latency             = 0;
+int update_audio_latency                 = false;
+
+int should_skip_frame                    = 0;
+
 int game_index = -1;
 unsigned short *gp2x_screen15;
 int thread_done = 0;
@@ -151,10 +165,87 @@ static bool libretro_supports_bitmasks = false;
 
 unsigned skip_disclaimer = 0;
 
-static void update_variables(void)
+static void retro_audio_buff_status_cb(
+      bool active, unsigned occupancy, bool underrun_likely)
+{
+   retro_audio_buff_active    = active;
+   retro_audio_buff_occupancy = occupancy;
+   retro_audio_buff_underrun  = underrun_likely;
+}
+
+static void retro_set_audio_buff_status_cb(void)
+{
+   if (frameskip_type > 0)
+   {
+      struct retro_audio_buffer_status_callback buf_status_cb;
+
+      buf_status_cb.callback = retro_audio_buff_status_cb;
+      if (!environ_cb(RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK,
+            &buf_status_cb))
+      {
+         retro_audio_buff_active    = false;
+         retro_audio_buff_occupancy = 0;
+         retro_audio_buff_underrun  = false;
+         retro_audio_latency        = 0;
+      }
+      else
+      {
+         /* Frameskip is enabled - increase frontend
+          * audio latency to minimise potential
+          * buffer underruns */
+         uint32_t frame_time_usec = 1000000.0 / Machine->drv->frames_per_second;
+
+         /* Set latency to 6x current frame time... */
+         retro_audio_latency = (unsigned)(6 * frame_time_usec / 1000);
+
+         /* ...then round up to nearest multiple of 32 */
+         retro_audio_latency = (retro_audio_latency + 0x1F) & ~0x1F;
+      }
+   }
+   else
+   {
+      environ_cb(RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK, NULL);
+      retro_audio_latency = 0;
+   }
+
+   update_audio_latency = true;
+}
+
+static void update_variables(bool first_run)
 {
     struct retro_variable var;
-    
+    bool prev_frameskip_type;
+
+    var.key = "mame2000-frameskip";
+    var.value = NULL;
+
+    prev_frameskip_type = frameskip_type;
+    frameskip_type      = 0;
+
+    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+    {
+       if (strcmp(var.value, "auto") == 0)
+          frameskip_type = 1;
+       if (strcmp(var.value, "threshold") == 0)
+          frameskip_type = 2;
+    }
+
+    var.key = "mame2000-frameskip_threshold";
+    var.value = NULL;
+
+    frameskip_threshold = 30;
+
+    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+       frameskip_threshold = strtol(var.value, NULL, 10);
+
+    var.key = "mame2000-frameskip_interval";
+    var.value = NULL;
+
+    frameskip_interval = 1;
+
+    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+       frameskip_interval = strtol(var.value, NULL, 10);
+
     var.value = NULL;
     var.key = "mame2000-skip_disclaimer";
     
@@ -180,11 +271,19 @@ static void update_variables(void)
     }
     else
         global_showinfo = 0;
+
+   /* Reinitialise frameskipping, if required */
+   if (!first_run &&
+       ((frameskip_type     != prev_frameskip_type)))
+      retro_set_audio_buff_status_cb();
 }
 
 void retro_set_environment(retro_environment_t cb)
 {
    static const struct retro_variable vars[] = {
+      { "mame2000-frameskip", "Frameskip ; disabled|auto|threshold" },
+      { "mame2000-frameskip_threshold", "Frameskip Threshold (%); 30|40|50|60" },
+      { "mame2000-frameskip_interval", "Frameskip Interval; 1|2|3|4|5|6|7|8|9" },
       { "mame2000-skip_disclaimer", "Skip Disclaimer; enabled|disabled" },
       { "mame2000-show_gameinfo", "Show Game Information; disabled|enabled" },
       { NULL, NULL },
@@ -475,7 +574,7 @@ void retro_init(void)
    libretro_mutex = slock_new();
 #endif
    init_joy_list();
-   update_variables();
+   update_variables(true);
 
    if (environ_cb(RETRO_ENVIRONMENT_GET_INPUT_BITMASKS, NULL))
       libretro_supports_bitmasks = true;
@@ -496,6 +595,14 @@ void retro_deinit(void)
 #endif
 
    libretro_supports_bitmasks = false;
+   frameskip_type             = 0;
+   frameskip_threshold        = 0;
+   frameskip_counter          = 0;
+   retro_audio_buff_active    = false;
+   retro_audio_buff_occupancy = 0;
+   retro_audio_buff_underrun  = false;
+   retro_audio_latency        = 0;
+   update_audio_latency       = false;
 }
 
 unsigned retro_api_version(void)
@@ -560,9 +667,13 @@ void retro_run(void)
    update_input();
 
    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
-      update_variables();
+      update_variables(false);
+
+   if (should_skip_frame)
+      video_cb(NULL, gfx_width, gfx_height, gfx_width * 2);
+   else
+      video_cb(gp2x_screen15, gfx_width, gfx_height, gfx_width * 2);
 
-   video_cb(gp2x_screen15, gfx_width, gfx_height, gfx_width * 2);
    if (samples_per_frame)
    {
       if (usestereo)
@@ -584,6 +695,19 @@ void retro_run(void)
 #ifndef WANT_LIBCO
    unlock_mame();
 #endif
+
+   /* If frameskip/timing settings have changed,
+    * update frontend audio latency
+    * > Can do this before or after the frameskip
+    *   check, but doing it after means we at least
+    *   retain the current frame's audio output */
+   if (update_audio_latency)
+   {
+      environ_cb(RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY,
+                 &retro_audio_latency);
+      update_audio_latency = false;
+   }
+
 }
 
 bool retro_load_game(const struct retro_game_info *info)
@@ -895,6 +1019,7 @@ bool retro_load_game(const struct retro_game_info *info)
    run_thread = sthread_create(run_thread_proc, NULL);
 #endif
 
+   retro_set_audio_buff_status_cb();
    return true;
 }
 
diff --git a/src/libretro/video.c b/src/libretro/video.c
index ce13ea0..f97ac05 100644
--- a/src/libretro/video.c
+++ b/src/libretro/video.c
@@ -8,6 +8,17 @@ extern int isIpad;
 extern int emulated_width;
 extern int emulated_height;
 extern int safe_render_path;
+
+extern unsigned frameskip_type;
+extern unsigned frameskip_threshold;
+extern unsigned frameskip_counter;
+extern unsigned frameskip_interval;
+
+extern int retro_audio_buff_active;
+extern unsigned retro_audio_buff_occupancy;
+extern int retro_audio_buff_underrun;
+extern int should_skip_frame;
+
 int iOS_exitPause = 0;
 int iOS_cropVideo = 0;
 int iOS_aspectRatio = 0;
@@ -793,7 +804,7 @@ static INLINE void pan_display(void)
 
 int osd_skip_this_frame(void)
 {
-   return 0;
+   return should_skip_frame;
 }
 
 /* Update the display. */
@@ -902,6 +913,41 @@ void osd_update_video_and_audio(struct osd_bitmap *bitmap)
 	/* Check for PGUP, PGDN and pan screen */
 	pan_display();
 
+	should_skip_frame = 0;
+	/* Check whether current frame should
+	 * be skipped */
+	if ((frameskip_type > 0) &&
+	    retro_audio_buff_active)
+	{
+		int skip_frame;
+
+		switch (frameskip_type)
+		{
+		case 1: /* auto */
+			skip_frame = retro_audio_buff_underrun;
+			break;
+		case 2: /* threshold */
+			skip_frame = (retro_audio_buff_occupancy < frameskip_threshold);
+			break;
+		default:
+			skip_frame = 0;
+			break;
+		}
+
+		if (skip_frame)
+		{
+			if(frameskip_counter < frameskip_interval)
+			{
+				should_skip_frame = 1;
+				frameskip_counter++;
+			}
+			else
+				frameskip_counter = 0;
+		}
+		else
+			frameskip_counter = 0;
+	}
+
    hook_video_done();
 }