cff531af |
1 | /*\r |
2 | * PicoDrive\r |
3 | * (C) notaz, 2006-2010\r |
15cc45c0 |
4 | * (C) irixxxx, 2019-2024\r |
cff531af |
5 | *\r |
6 | * This work is licensed under the terms of MAME license.\r |
7 | * See COPYING file in the top-level directory.\r |
8 | */\r |
697746df |
9 | \r |
10 | #include <stdio.h>\r |
11 | #include <unistd.h>\r |
8b60ec30 |
12 | #include <sys/mman.h>\r |
697746df |
13 | \r |
e743be20 |
14 | #include "../libpicofe/menu.h"\r |
15 | #include "../libpicofe/plat.h"\r |
697746df |
16 | #include "../common/emu.h"\r |
697746df |
17 | #include "../common/arm_utils.h"\r |
d5d17782 |
18 | #include "../common/upscale.h"\r |
90f0dedf |
19 | #include "../common/version.h"\r |
697746df |
20 | \r |
21 | #include <pico/pico_int.h>\r |
22 | \r |
23 | \r |
fcdefcf6 |
24 | const char *renderer_names[] = { "16bit accurate", " 8bit accurate", " 8bit fast", NULL };\r |
25 | const char *renderer_names32x[] = { "accurate", "faster", "fastest", NULL };\r |
5a681086 |
26 | enum renderer_types { RT_16BIT, RT_8BIT_ACC, RT_8BIT_FAST, RT_COUNT };\r |
697746df |
27 | \r |
d5d17782 |
28 | static int out_x, out_y, out_w, out_h; // renderer output in render buffer\r |
29 | static int screen_x, screen_y, screen_w, screen_h; // final render destination \r |
30 | static int render_bg; // force 16bit mode for bg render\r |
f55ce7bf |
31 | static u16 *ghost_buf; // backbuffer to simulate LCD ghosting\r |
697746df |
32 | \r |
33 | void pemu_prep_defconfig(void)\r |
34 | {\r |
697746df |
35 | }\r |
36 | \r |
37 | void pemu_validate_config(void)\r |
38 | {\r |
31efd454 |
39 | #if !defined(DRC_SH2)\r |
93f9619e |
40 | PicoIn.opt &= ~POPT_EN_DRC;\r |
05eb243d |
41 | #endif\r |
697746df |
42 | }\r |
43 | \r |
43f79c5b |
44 | #define is_16bit_mode() \\r |
d5d17782 |
45 | (currentConfig.renderer == RT_16BIT || (PicoIn.AHW & PAHW_32X) || render_bg)\r |
43f79c5b |
46 | \r |
47 | static int get_renderer(void)\r |
48 | {\r |
49 | if (PicoIn.AHW & PAHW_32X)\r |
50 | return currentConfig.renderer32x;\r |
51 | else\r |
52 | return currentConfig.renderer;\r |
53 | }\r |
54 | \r |
55 | static void change_renderer(int diff)\r |
56 | {\r |
57 | int *r;\r |
58 | if (PicoIn.AHW & PAHW_32X)\r |
59 | r = ¤tConfig.renderer32x;\r |
60 | else\r |
61 | r = ¤tConfig.renderer;\r |
62 | *r += diff;\r |
63 | \r |
64 | if (*r >= RT_COUNT)\r |
65 | *r = 0;\r |
66 | else if (*r < 0)\r |
67 | *r = RT_COUNT - 1;\r |
68 | }\r |
69 | \r |
697746df |
70 | static void draw_cd_leds(void)\r |
71 | {\r |
72 | int led_reg, pitch, scr_offs, led_offs;\r |
73 | led_reg = Pico_mcd->s68k_regs[0];\r |
74 | \r |
7a7265ee |
75 | pitch = g_screen_ppitch;\r |
697746df |
76 | led_offs = 4;\r |
77 | scr_offs = pitch * 2 + 4;\r |
78 | \r |
758abbeb |
79 | #define p(x) px[(x)*2 >> 2] = px[((x)*2 >> 2) + 1]\r |
80 | // 16-bit modes\r |
f821bb70 |
81 | uint32_t *px = (uint32_t *)((short *)g_screen_ptr + scr_offs);\r |
82 | uint32_t col_g = (led_reg & 2) ? 0x06000600 : 0;\r |
83 | uint32_t col_r = (led_reg & 1) ? 0xc000c000 : 0;\r |
758abbeb |
84 | p(pitch*0) = p(pitch*1) = p(pitch*2) = col_g;\r |
85 | p(pitch*0 + led_offs) = p(pitch*1 + led_offs) = p(pitch*2 + led_offs) = col_r;\r |
86 | #undef p\r |
697746df |
87 | }\r |
88 | \r |
dca20eff |
89 | static void draw_pico_ptr(void)\r |
90 | {\r |
c87e36d7 |
91 | int up = (PicoPicohw.pen_pos[0]|PicoPicohw.pen_pos[1]) & 0x8000;\r |
92 | int o = (up ? 0x0000 : 0xffff), _ = (up ? 0xffff : 0x0000);\r |
dca20eff |
93 | int pitch = g_screen_ppitch;\r |
94 | u16 *p = g_screen_ptr;\r |
95 | int x = pico_pen_x, y = pico_pen_y;\r |
15cc45c0 |
96 | // storyware pages are actually squished, 2:1\r |
97 | int h = (pico_inp_mode == 1 ? 160 : out_h);\r |
98 | if (h < 224) y++;\r |
dca20eff |
99 | \r |
c87e36d7 |
100 | x = (x * out_w * ((1ULL<<32) / 320 + 1)) >> 32;\r |
15cc45c0 |
101 | y = (y * h * ((1ULL<<32) / 224 + 1)) >> 32;\r |
dca20eff |
102 | p += (screen_y+y)*pitch + (screen_x+x);\r |
103 | \r |
15cc45c0 |
104 | p[-pitch-1] ^= o; p[-pitch] ^= _; p[-pitch+1] ^= _; p[-pitch+2] ^= o;\r |
105 | p[-1] ^= _; p[0] ^= o; p[1] ^= o; p[2] ^= _;\r |
106 | p[pitch-1] ^= _; p[pitch] ^= o; p[pitch+1] ^= o; p[pitch+2] ^= _;\r |
107 | p[2*pitch-1]^= o; p[2*pitch]^= _; p[2*pitch+1]^= _; p[2*pitch+2]^= o;\r |
dca20eff |
108 | }\r |
109 | \r |
d5d17782 |
110 | /* render/screen buffer handling:\r |
111 | * In 16 bit mode, render output is directly placed in the screen buffer.\r |
112 | * SW scaling is handled in renderer (x) and in vscaling callbacks here (y).\r |
113 | * In 8 bit modes, output goes to the internal Draw2FB buffer in alternate\r |
114 | * renderer format (8 pix overscan at left/top/bottom), left aligned (DIS_32C).\r |
115 | * It is converted to 16 bit and SW scaled in pemu_finalize_frame.\r |
116 | *\r |
117 | * HW scaling always aligns the image to the left/top, since selecting an area\r |
118 | * for display isn't always possible.\r |
119 | */\r |
120 | \r |
466fa079 |
121 | static inline u16 *screen_buffer(u16 *buf)\r |
d5d17782 |
122 | {\r |
ce79590a |
123 | return buf + screen_y * g_screen_ppitch + screen_x -\r |
124 | (out_y * g_screen_ppitch + out_x);\r |
d5d17782 |
125 | }\r |
126 | \r |
127 | void screen_blit(u16 *pd, int pp, u8* ps, int ss, u16 *pal)\r |
832faed3 |
128 | {\r |
d5d17782 |
129 | typedef void (*upscale_t)\r |
130 | (u16 *di,int ds, u8 *si,int ss, int w,int h, u16 *pal);\r |
466fa079 |
131 | static const upscale_t upscale_256_224_hv[] = {\r |
d5d17782 |
132 | upscale_rgb_nn_x_4_5_y_16_17, upscale_rgb_snn_x_4_5_y_16_17,\r |
133 | upscale_rgb_bl2_x_4_5_y_16_17, upscale_rgb_bl4_x_4_5_y_16_17,\r |
134 | };\r |
b01c1ec5 |
135 | static const upscale_t upscale_256_____h[] = {\r |
d5d17782 |
136 | upscale_rgb_nn_x_4_5, upscale_rgb_snn_x_4_5,\r |
137 | upscale_rgb_bl2_x_4_5, upscale_rgb_bl4_x_4_5,\r |
138 | };\r |
b01c1ec5 |
139 | static const upscale_t upscale_____224_v[] = {\r |
d5d17782 |
140 | upscale_rgb_nn_y_16_17, upscale_rgb_snn_y_16_17,\r |
141 | upscale_rgb_bl2_y_16_17, upscale_rgb_bl4_y_16_17,\r |
142 | };\r |
466fa079 |
143 | static const upscale_t upscale_160_144_hv[] = {\r |
144 | upscale_rgb_nn_x_1_2_y_3_5, upscale_rgb_nn_x_1_2_y_3_5,\r |
145 | upscale_rgb_bl2_x_1_2_y_3_5, upscale_rgb_bl4_x_1_2_y_3_5,\r |
146 | };\r |
b01c1ec5 |
147 | static const upscale_t upscale_160_____h[] = {\r |
466fa079 |
148 | upscale_rgb_nn_x_1_2, upscale_rgb_nn_x_1_2,\r |
149 | upscale_rgb_bl2_x_1_2, upscale_rgb_bl2_x_1_2,\r |
150 | };\r |
b01c1ec5 |
151 | static const upscale_t upscale_____144_v[] = {\r |
466fa079 |
152 | upscale_rgb_nn_y_3_5, upscale_rgb_nn_y_3_5,\r |
153 | upscale_rgb_bl2_y_3_5, upscale_rgb_bl4_y_3_5,\r |
154 | };\r |
155 | const upscale_t *upscale;\r |
d5d17782 |
156 | int y;\r |
157 | \r |
158 | // handle software upscaling\r |
159 | upscale = NULL;\r |
b01c1ec5 |
160 | if (currentConfig.scaling == EOPT_SCALE_SW && out_w <= 256) {\r |
466fa079 |
161 | if (currentConfig.vscaling == EOPT_SCALE_SW && out_h <= 224)\r |
162 | // h+v scaling\r |
96948bdf |
163 | upscale = out_w >= 240 ? upscale_256_224_hv: upscale_160_144_hv;\r |
466fa079 |
164 | else\r |
165 | // h scaling\r |
96948bdf |
166 | upscale = out_w >= 240 ? upscale_256_____h : upscale_160_____h;\r |
466fa079 |
167 | } else if (currentConfig.vscaling == EOPT_SCALE_SW && out_h <= 224)\r |
168 | // v scaling\r |
96948bdf |
169 | upscale = out_w >= 240 ? upscale_____224_v : upscale_____144_v;\r |
466fa079 |
170 | if (!upscale) {\r |
d5d17782 |
171 | // no scaling\r |
172 | for (y = 0; y < out_h; y++)\r |
173 | h_copy(pd, pp, ps, 328, out_w, f_pal);\r |
174 | return;\r |
175 | }\r |
176 | \r |
177 | upscale[currentConfig.filter & 0x3](pd, pp, ps, ss, out_w, out_h, pal);\r |
832faed3 |
178 | }\r |
179 | \r |
d08e7326 |
180 | void pemu_finalize_frame(const char *fps, const char *notice)\r |
697746df |
181 | {\r |
43f79c5b |
182 | if (!is_16bit_mode()) {\r |
183 | // convert the 8 bit CLUT output to 16 bit RGB\r |
d5d17782 |
184 | u16 *pd = screen_buffer(g_screen_ptr) +\r |
ce79590a |
185 | out_y * g_screen_ppitch + out_x;\r |
186 | u8 *ps = Pico.est.Draw2FB + out_y * 328 + out_x + 8;\r |
b1a047c9 |
187 | \r |
188 | PicoDrawUpdateHighPal();\r |
d5d17782 |
189 | \r |
96948bdf |
190 | if (out_w == 248 && currentConfig.scaling == EOPT_SCALE_SW)\r |
191 | pd += (320 - out_w*320/256) / 2; // SMS with 1st tile blanked, recenter\r |
d5d17782 |
192 | screen_blit(pd, g_screen_ppitch, ps, 328, Pico.est.HighPal);\r |
5a681086 |
193 | }\r |
194 | \r |
f55ce7bf |
195 | if (currentConfig.ghosting && out_h == 144) {\r |
196 | // GG LCD ghosting emulation\r |
197 | u16 *pd = screen_buffer(g_screen_ptr) +\r |
198 | out_y * g_screen_ppitch + out_x;\r |
199 | u16 *ps = ghost_buf;\r |
200 | int y, h = currentConfig.vscaling == EOPT_SCALE_SW ? 240:out_h;\r |
201 | int w = currentConfig.scaling == EOPT_SCALE_SW ? 320:out_w;\r |
15cc45c0 |
202 | \r |
44e4bf2b |
203 | if (currentConfig.ghosting == 1)\r |
204 | for (y = 0; y < h; y++) {\r |
f55ce7bf |
205 | v_blend((u32 *)pd, (u32 *)ps, w/2, p_075_round);\r |
44e4bf2b |
206 | pd += g_screen_ppitch;\r |
207 | ps += w;\r |
208 | }\r |
209 | else\r |
210 | for (y = 0; y < h; y++) {\r |
f55ce7bf |
211 | v_blend((u32 *)pd, (u32 *)ps, w/2, p_05_round);\r |
44e4bf2b |
212 | pd += g_screen_ppitch;\r |
213 | ps += w;\r |
214 | }\r |
f55ce7bf |
215 | }\r |
216 | \r |
15cc45c0 |
217 | if (PicoIn.AHW & PAHW_PICO) {\r |
218 | int h = currentConfig.vscaling == EOPT_SCALE_SW ? 240:out_h;\r |
219 | int w = currentConfig.scaling == EOPT_SCALE_SW ? 320:out_w;\r |
220 | u16 *pd = screen_buffer(g_screen_ptr) + out_y*g_screen_ppitch + out_x;\r |
221 | \r |
222 | if (pico_inp_mode)\r |
223 | emu_pico_overlay(pd, w, h, g_screen_ppitch);\r |
224 | if (pico_inp_mode /*== 2 || overlay*/)\r |
225 | draw_pico_ptr();\r |
226 | }\r |
227 | \r |
758abbeb |
228 | if (notice)\r |
229 | emu_osd_text16(4, g_screen_height - 8, notice);\r |
230 | if (currentConfig.EmuOpt & EOPT_SHOW_FPS)\r |
231 | emu_osd_text16(g_screen_width - 60, g_screen_height - 8, fps);\r |
93f9619e |
232 | if ((PicoIn.AHW & PAHW_MCD) && (currentConfig.EmuOpt & EOPT_EN_CD_LEDS))\r |
697746df |
233 | draw_cd_leds();\r |
697746df |
234 | }\r |
235 | \r |
758abbeb |
236 | void plat_video_set_buffer(void *buf)\r |
237 | {\r |
43f79c5b |
238 | if (is_16bit_mode())\r |
d5d17782 |
239 | PicoDrawSetOutBuf(screen_buffer(buf), g_screen_ppitch * 2);\r |
758abbeb |
240 | }\r |
241 | \r |
5a681086 |
242 | static void apply_renderer(void)\r |
243 | {\r |
96948bdf |
244 | PicoIn.opt |= POPT_DIS_32C_BORDER;\r |
245 | PicoIn.opt &= ~(POPT_ALT_RENDERER|POPT_EN_SOFTSCALE);\r |
1bbe9abf |
246 | if (is_16bit_mode()) {\r |
c3fcdf3f |
247 | if (currentConfig.scaling == EOPT_SCALE_SW)\r |
1bbe9abf |
248 | PicoIn.opt |= POPT_EN_SOFTSCALE;\r |
c3fcdf3f |
249 | PicoIn.filter = currentConfig.filter;\r |
96948bdf |
250 | }\r |
d1ae0810 |
251 | \r |
43f79c5b |
252 | switch (get_renderer()) {\r |
5a681086 |
253 | case RT_16BIT:\r |
d5d17782 |
254 | // 32X uses line mode for vscaling with accurate renderer, since\r |
255 | // the MD VDP layer must be unscaled and merging the scaled 32X\r |
256 | // image data will fail.\r |
257 | PicoDrawSetOutFormat(PDF_RGB555,\r |
258 | (PicoIn.AHW & PAHW_32X) && currentConfig.vscaling);\r |
259 | PicoDrawSetOutBuf(screen_buffer(g_screen_ptr), g_screen_ppitch * 2);\r |
5a681086 |
260 | break;\r |
261 | case RT_8BIT_ACC:\r |
d5d17782 |
262 | // for simplification the 8 bit accurate renderer uses the same\r |
263 | // storage format as the fast renderer\r |
5a681086 |
264 | PicoDrawSetOutFormat(PDF_8BIT, 0);\r |
35247900 |
265 | PicoDrawSetOutBuf(Pico.est.Draw2FB, 328);\r |
5a681086 |
266 | break;\r |
267 | case RT_8BIT_FAST:\r |
93f9619e |
268 | PicoIn.opt |= POPT_ALT_RENDERER;\r |
5a681086 |
269 | PicoDrawSetOutFormat(PDF_NONE, 0);\r |
270 | break;\r |
271 | }\r |
272 | \r |
93f9619e |
273 | if (PicoIn.AHW & PAHW_32X)\r |
d5d17782 |
274 | PicoDrawSetOutBuf(screen_buffer(g_screen_ptr), g_screen_ppitch * 2);\r |
b1a047c9 |
275 | Pico.m.dirtyPal = 1;\r |
5a681086 |
276 | }\r |
277 | \r |
278 | void plat_video_toggle_renderer(int change, int is_menu)\r |
697746df |
279 | {\r |
43f79c5b |
280 | change_renderer(change);\r |
ebd9c86a |
281 | plat_video_clear_buffers();\r |
5a681086 |
282 | \r |
43f79c5b |
283 | if (!is_menu) {\r |
5a681086 |
284 | apply_renderer();\r |
285 | \r |
43f79c5b |
286 | if (PicoIn.AHW & PAHW_32X)\r |
287 | emu_status_msg(renderer_names32x[get_renderer()]);\r |
288 | else\r |
289 | emu_status_msg(renderer_names[get_renderer()]);\r |
290 | }\r |
697746df |
291 | }\r |
292 | \r |
697746df |
293 | void plat_status_msg_clear(void)\r |
294 | {\r |
69b7b264 |
295 | plat_video_clear_status();\r |
697746df |
296 | }\r |
297 | \r |
298 | void plat_status_msg_busy_next(const char *msg)\r |
299 | {\r |
300 | plat_status_msg_clear();\r |
d08e7326 |
301 | pemu_finalize_frame("", msg);\r |
302 | plat_video_flip();\r |
697746df |
303 | emu_status_msg("");\r |
304 | reset_timing = 1;\r |
305 | }\r |
306 | \r |
307 | void plat_status_msg_busy_first(const char *msg)\r |
308 | {\r |
697746df |
309 | plat_status_msg_busy_next(msg);\r |
310 | }\r |
311 | \r |
312 | void plat_update_volume(int has_changed, int is_up)\r |
313 | {\r |
314 | }\r |
315 | \r |
d5d17782 |
316 | void pemu_sound_start(void)\r |
317 | {\r |
318 | emu_sound_start();\r |
319 | }\r |
320 | \r |
321 | void plat_debug_cat(char *str)\r |
322 | {\r |
323 | }\r |
324 | \r |
45285368 |
325 | void pemu_forced_frame(int no_scale, int do_emu)\r |
697746df |
326 | {\r |
d5d17782 |
327 | int hs = currentConfig.scaling, vs = currentConfig.vscaling;\r |
832faed3 |
328 | \r |
d5d17782 |
329 | // create centered and sw scaled (if scaling enabled) 16 bit output\r |
627648e4 |
330 | PicoIn.opt &= ~POPT_DIS_32C_BORDER;\r |
697746df |
331 | Pico.m.dirtyPal = 1;\r |
d5d17782 |
332 | if (currentConfig.scaling) currentConfig.scaling = EOPT_SCALE_SW;\r |
333 | if (currentConfig.vscaling) currentConfig.vscaling = EOPT_SCALE_SW;\r |
a4edca53 |
334 | \r |
d5d17782 |
335 | // render a frame in 16 bit mode\r |
336 | render_bg = 1;\r |
ce79590a |
337 | emu_cmn_forced_frame(no_scale, do_emu, screen_buffer(g_screen_ptr));\r |
d5d17782 |
338 | render_bg = 0;\r |
697746df |
339 | \r |
23e47196 |
340 | g_menubg_src_ptr = realloc(g_menubg_src_ptr, g_screen_height * g_screen_ppitch * 2);\r |
341 | memcpy(g_menubg_src_ptr, g_screen_ptr, g_screen_height * g_screen_ppitch * 2);\r |
d5d17782 |
342 | currentConfig.scaling = hs, currentConfig.vscaling = vs;\r |
697746df |
343 | }\r |
344 | \r |
d5d17782 |
345 | /* vertical sw scaling, 16 bit mode */\r |
346 | static int vscale_state;\r |
347 | \r |
348 | static int cb_vscaling_begin(unsigned int line)\r |
697746df |
349 | {\r |
d5d17782 |
350 | // at start of new frame?\r |
466fa079 |
351 | if (line <= out_y) {\r |
352 | // set y frame offset (see emu_video_mode_change)\r |
ce79590a |
353 | Pico.est.DrawLineDest = screen_buffer(g_screen_ptr) +\r |
466fa079 |
354 | (out_y * g_screen_ppitch /*+ out_x*/);\r |
d5d17782 |
355 | vscale_state = 0;\r |
466fa079 |
356 | return out_y - line;\r |
357 | } else if (line > out_y + out_h)\r |
358 | return 1;\r |
359 | \r |
d5d17782 |
360 | return 0;\r |
697746df |
361 | }\r |
362 | \r |
d5d17782 |
363 | static int cb_vscaling_nop(unsigned int line)\r |
364 | {\r |
365 | return 0;\r |
366 | }\r |
367 | \r |
368 | static int cb_vscaling_end(unsigned int line)\r |
697746df |
369 | {\r |
f55ce7bf |
370 | u16 *dest = (u16 *)Pico.est.DrawLineDest + out_x;\r |
371 | // helpers for 32 bit operation (2 pixels at once):\r |
372 | u32 *dest32 = (u32 *)dest;\r |
373 | int pp = g_screen_ppitch;\r |
466fa079 |
374 | \r |
375 | if (out_h == 144)\r |
376 | switch (currentConfig.filter) {\r |
f55ce7bf |
377 | case 0: v_upscale_nn_3_5(dest32, pp/2, out_w/2, vscale_state);\r |
466fa079 |
378 | break;\r |
f55ce7bf |
379 | default: v_upscale_snn_3_5(dest32, pp/2, out_w/2, vscale_state);\r |
466fa079 |
380 | break;\r |
381 | }\r |
382 | else\r |
383 | switch (currentConfig.filter) {\r |
f55ce7bf |
384 | case 3: v_upscale_bl4_16_17(dest32, pp/2, out_w/2, vscale_state);\r |
466fa079 |
385 | break;\r |
f55ce7bf |
386 | case 2: v_upscale_bl2_16_17(dest32, pp/2, out_w/2, vscale_state);\r |
466fa079 |
387 | break;\r |
f55ce7bf |
388 | case 1: v_upscale_snn_16_17(dest32, pp/2, out_w/2, vscale_state);\r |
466fa079 |
389 | break;\r |
f55ce7bf |
390 | default: v_upscale_nn_16_17(dest32, pp/2, out_w/2, vscale_state);\r |
466fa079 |
391 | break;\r |
392 | }\r |
f55ce7bf |
393 | Pico.est.DrawLineDest = (u16 *)dest32 - out_x;\r |
d5d17782 |
394 | return 0;\r |
697746df |
395 | }\r |
396 | \r |
d5d17782 |
397 | void emu_video_mode_change(int start_line, int line_count, int start_col, int col_count)\r |
697746df |
398 | {\r |
d5d17782 |
399 | // relative position in core fb and screen fb\r |
400 | out_y = start_line; out_x = start_col;\r |
401 | out_h = line_count; out_w = col_count;\r |
402 | \r |
db8af214 |
403 | if (! render_bg)\r |
404 | plat_video_loop_prepare(); // recalculates g_screen_w/h\r |
d5d17782 |
405 | PicoDrawSetCallbacks(NULL, NULL);\r |
ce79590a |
406 | // center output in screen\r |
407 | screen_w = g_screen_width, screen_x = (screen_w - out_w)/2;\r |
408 | screen_h = g_screen_height, screen_y = (screen_h - out_h)/2;\r |
409 | \r |
d5d17782 |
410 | switch (currentConfig.scaling) {\r |
411 | case EOPT_SCALE_HW:\r |
96948bdf |
412 | // mind aspect ratio for SMS with 1st column blanked\r |
413 | screen_w = (out_w == 248 ? 256 : out_w);\r |
414 | screen_x = (screen_w - out_w)/2;\r |
d5d17782 |
415 | break;\r |
ce79590a |
416 | case EOPT_SCALE_SW:\r |
417 | screen_x = (screen_w - 320)/2;\r |
d5d17782 |
418 | break;\r |
419 | }\r |
420 | switch (currentConfig.vscaling) {\r |
421 | case EOPT_SCALE_HW:\r |
466fa079 |
422 | screen_h = (out_h < 224 && out_h > 144 ? 224 : out_h);\r |
ce79590a |
423 | screen_y = 0;\r |
424 | // NTSC always has 224 visible lines, anything smaller has bars\r |
466fa079 |
425 | if (out_h < 224 && out_h > 144)\r |
ce79590a |
426 | screen_y += (224 - out_h)/2;\r |
d5d17782 |
427 | // handle vertical centering for 16 bit mode\r |
d5d17782 |
428 | if (is_16bit_mode())\r |
ce79590a |
429 | PicoDrawSetCallbacks(cb_vscaling_begin,cb_vscaling_nop);\r |
d5d17782 |
430 | break;\r |
431 | case EOPT_SCALE_SW:\r |
44e4bf2b |
432 | screen_y = (screen_h - 240)/2 + (out_h < 240 && out_h > 144);\r |
d5d17782 |
433 | // NTSC always has 224 visible lines, anything smaller has bars\r |
466fa079 |
434 | if (out_h < 224 && out_h > 144)\r |
ce79590a |
435 | screen_y += (224 - out_h)/2;\r |
d5d17782 |
436 | // in 16 bit mode sw scaling is divided between core and platform\r |
437 | if (is_16bit_mode() && out_h < 240)\r |
ce79590a |
438 | PicoDrawSetCallbacks(cb_vscaling_begin,cb_vscaling_end);\r |
d5d17782 |
439 | break;\r |
440 | }\r |
441 | \r |
db8af214 |
442 | if (! render_bg)\r |
443 | plat_video_set_size(screen_w, screen_h);\r |
d5d17782 |
444 | \r |
f8aaa200 |
445 | if (screen_w < g_screen_width)\r |
446 | screen_x = (g_screen_width - screen_w)/2;\r |
447 | if (screen_h < g_screen_height) {\r |
448 | screen_y = (g_screen_height - screen_h)/2;\r |
449 | // NTSC always has 224 visible lines, anything smaller has bars\r |
450 | if (out_h < 224 && out_h > 144)\r |
451 | screen_y += (224 - out_h)/2;\r |
452 | }\r |
453 | \r |
23e47196 |
454 | plat_video_set_buffer(g_screen_ptr);\r |
455 | \r |
f55ce7bf |
456 | // create a backing buffer for emulating the bad GG lcd display\r |
457 | if (currentConfig.ghosting && out_h == 144) {\r |
458 | int h = currentConfig.vscaling == EOPT_SCALE_SW ? 240:out_h;\r |
459 | int w = currentConfig.scaling == EOPT_SCALE_SW ? 320:out_w;\r |
460 | ghost_buf = realloc(ghost_buf, w * h * 2);\r |
461 | memset(ghost_buf, 0, w * h * 2);\r |
462 | }\r |
463 | \r |
697746df |
464 | // clear whole screen in all buffers\r |
43f79c5b |
465 | if (!is_16bit_mode())\r |
7980d477 |
466 | memset32(Pico.est.Draw2FB, 0xe0e0e0e0, (320+8) * (8+240+8) / 4);\r |
69b7b264 |
467 | plat_video_clear_buffers();\r |
697746df |
468 | }\r |
469 | \r |
470 | void pemu_loop_prep(void)\r |
471 | {\r |
5a681086 |
472 | apply_renderer();\r |
69b7b264 |
473 | plat_video_clear_buffers();\r |
697746df |
474 | }\r |
475 | \r |
476 | void pemu_loop_end(void)\r |
477 | {\r |
697746df |
478 | /* do one more frame for menu bg */\r |
5aa57006 |
479 | plat_video_set_shadow(320, 240);\r |
45285368 |
480 | pemu_forced_frame(0, 1);\r |
f8aaa200 |
481 | g_menubg_src_w = g_screen_width;\r |
482 | g_menubg_src_h = g_screen_height;\r |
483 | g_menubg_src_pp = g_screen_ppitch;\r |
f55ce7bf |
484 | if (ghost_buf) {\r |
485 | free(ghost_buf);\r |
486 | ghost_buf = NULL;\r |
487 | }\r |
697746df |
488 | }\r |
489 | \r |
490 | void plat_wait_till_us(unsigned int us_to)\r |
491 | {\r |
492 | unsigned int now;\r |
493 | \r |
494 | now = plat_get_ticks_us();\r |
495 | \r |
496 | while ((signed int)(us_to - now) > 512)\r |
497 | {\r |
498 | usleep(1024);\r |
499 | now = plat_get_ticks_us();\r |
500 | }\r |
501 | }\r |
502 | \r |
df925153 |
503 | void *plat_mem_get_for_drc(size_t size)\r |
504 | {\r |
8b60ec30 |
505 | #ifdef MAP_JIT\r |
506 | // newer versions of OSX, IOS or TvOS need this\r |
507 | return plat_mmap(0, size, 1, 0);\r |
508 | #else\r |
df925153 |
509 | return NULL;\r |
8b60ec30 |
510 | #endif\r |
df925153 |
511 | }\r |