1 #include "rsx/rsx_intf.h"
2
3 #include <math.h>
4 #include <stdint.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include "boolean.h"
9 #include "libretro.h"
10
11 #include "beetle_psx_globals.h"
12 #include "libretro_cbs.h"
13 #include "libretro_options.h"
14 #include "mednafen/mednafen.h"
15 #include "mednafen/psx/gpu.h"
16 #include "mednafen/settings.h"
17
18 #ifdef RSX_DUMP
19 #include "rsx_dump.h"
20 #endif
21
22 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
23 #include "rsx_lib_gl.h"
24 #endif
25
26 #if defined(HAVE_VULKAN)
27 #include "rsx_lib_vulkan.h"
28 #endif
29
30 extern bool fast_pal;
31
32 static enum rsx_renderer_type rsx_type = RSX_SOFTWARE;
33
34 static bool gl_initialized = false;
35 static bool vk_initialized = false;
36
37 // GPU reset defaults
38 static int rsx_width_mode = WIDTH_MODE_256;
39 static int rsx_height_mode = HEIGHT_MODE_240;
40
rsx_soft_open(bool is_pal)41 static bool rsx_soft_open(bool is_pal)
42 {
43 content_is_pal = is_pal;
44 return true;
45 }
46
rsx_intf_set_environment(retro_environment_t cb)47 void rsx_intf_set_environment(retro_environment_t cb)
48 {
49 switch (rsx_type)
50 {
51 case RSX_SOFTWARE:
52 break;
53 case RSX_OPENGL:
54 break;
55 case RSX_VULKAN:
56 #if defined(HAVE_VULKAN)
57 rsx_vulkan_set_environment(cb);
58 #endif
59 break;
60 }
61 }
62
rsx_intf_set_video_refresh(retro_video_refresh_t cb)63 void rsx_intf_set_video_refresh(retro_video_refresh_t cb)
64 {
65 switch (rsx_type)
66 {
67 case RSX_SOFTWARE:
68 break;
69 case RSX_OPENGL:
70 break;
71 case RSX_VULKAN:
72 #if defined(HAVE_VULKAN)
73 rsx_vulkan_set_video_refresh(cb);
74 #endif
75 break;
76 }
77 }
78
rsx_intf_get_system_av_info(struct retro_system_av_info * info)79 void rsx_intf_get_system_av_info(struct retro_system_av_info *info)
80 {
81 switch (rsx_type)
82 {
83 case RSX_SOFTWARE:
84 memset(info, 0, sizeof(*info));
85 info->timing.fps = rsx_common_get_timing_fps();
86 info->timing.sample_rate = SOUND_FREQUENCY;
87 info->geometry.base_width = MEDNAFEN_CORE_GEOMETRY_BASE_W;
88 info->geometry.base_height = MEDNAFEN_CORE_GEOMETRY_BASE_H;
89 info->geometry.max_width = MEDNAFEN_CORE_GEOMETRY_MAX_W << psx_gpu_upscale_shift;
90 info->geometry.max_height = MEDNAFEN_CORE_GEOMETRY_MAX_H << psx_gpu_upscale_shift;
91 info->geometry.aspect_ratio = rsx_common_get_aspect_ratio(content_is_pal, crop_overscan,
92 MDFN_GetSettingI(content_is_pal ? "psx.slstartp" : "psx.slstart"),
93 MDFN_GetSettingI(content_is_pal ? "psx.slendp" : "psx.slend"),
94 aspect_ratio_setting, false, widescreen_hack, widescreen_hack_aspect_ratio_setting);
95 break;
96 case RSX_OPENGL:
97 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
98 rsx_gl_get_system_av_info(info);
99 #endif
100 break;
101 case RSX_VULKAN:
102 #if defined(HAVE_VULKAN)
103 rsx_vulkan_get_system_av_info(info);
104 #endif
105 break;
106 }
107 }
108
rsx_intf_is_type(void)109 enum rsx_renderer_type rsx_intf_is_type(void)
110 {
111 return rsx_type;
112 }
113
rsx_intf_dump_init(void)114 inline void rsx_intf_dump_init(void)
115 {
116 #if defined(RSX_DUMP)
117 {
118 const char *env = getenv("RSX_DUMP");
119 if (env)
120 rsx_dump_init(env);
121 }
122 #endif
123 }
124
rsx_intf_open(bool is_pal,bool force_software)125 bool rsx_intf_open(bool is_pal, bool force_software)
126 {
127 struct retro_variable var = {0};
128 bool software_selected = false;
129 vk_initialized = false;
130 gl_initialized = false;
131
132 enum force_renderer_type force_type = AUTO;
133
134 var.key = BEETLE_OPT(renderer);
135
136 if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
137 {
138 if (!strcmp(var.value, "software") || force_software)
139 software_selected = true;
140 else if (!strcmp(var.value, "hardware_gl"))
141 force_type = FORCE_OPENGL;
142 else if (!strcmp(var.value, "hardware_vk"))
143 force_type = FORCE_VULKAN;
144 }
145 else
146 {
147 /* If 'BEETLE_OPT(renderer)' option is not found, then
148 * we are running in software mode */
149 software_selected = true;
150 }
151
152 if (!software_selected)
153 {
154 /* Check for any hardware renderer forces before performing auto sequence */
155 if (force_type == FORCE_VULKAN)
156 {
157 #if defined (HAVE_VULKAN)
158 if (rsx_vulkan_open(is_pal))
159 {
160 rsx_type = RSX_VULKAN;
161 vk_initialized = true;
162 rsx_intf_dump_init();
163 return true;
164 }
165 else
166 {
167 MDFND_DispMessage(3, RETRO_LOG_ERROR,
168 RETRO_MESSAGE_TARGET_ALL, RETRO_MESSAGE_TYPE_NOTIFICATION,
169 "Could not force Vulkan renderer. Falling back to software renderer.");
170
171 goto soft;
172 }
173 #else
174 MDFND_DispMessage(3, RETRO_LOG_ERROR,
175 RETRO_MESSAGE_TARGET_ALL, RETRO_MESSAGE_TYPE_NOTIFICATION,
176 "Attempted to force Vulkan renderer, but core was built without it. Falling back to software renderer.");
177
178 goto soft;
179 #endif
180 }
181 else if (force_type == FORCE_OPENGL)
182 {
183 #if defined (HAVE_OPENGL) || defined(HAVE_OPENGLES)
184 if (rsx_gl_open(is_pal))
185 {
186 rsx_type = RSX_OPENGL;
187 gl_initialized = true;
188 rsx_intf_dump_init();
189 return true;
190 }
191 else
192 {
193 MDFND_DispMessage(3, RETRO_LOG_ERROR,
194 RETRO_MESSAGE_TARGET_ALL, RETRO_MESSAGE_TYPE_NOTIFICATION,
195 "Could not force OpenGL renderer. Falling back to software renderer.");
196
197 goto soft;
198 }
199 #else
200 MDFND_DispMessage(3, RETRO_LOG_ERROR,
201 RETRO_MESSAGE_TARGET_ALL, RETRO_MESSAGE_TYPE_NOTIFICATION,
202 "Attempted to force OpenGL renderer, but core was built without it. Falling back to software renderer.");
203
204 goto soft;
205 #endif
206 }
207 /* End forces section */
208
209 unsigned preferred = 0; // This will be set to RETRO_HW_CONTEXT_DUMMY if GET_PREFERRED_HW_RENDER is not supported by frontend
210 if (!environ_cb(RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER, &preferred))
211 {
212 preferred = RETRO_HW_CONTEXT_DUMMY;
213 }
214 /* If GET_PREFERRED_HW_RENDER is not supported by frontend, then we just go
215 * down the list attempting to open a hardware renderer until we get one */
216
217 #if defined(HAVE_VULKAN)
218 if ((preferred == RETRO_HW_CONTEXT_DUMMY ||
219 preferred == RETRO_HW_CONTEXT_VULKAN)
220 && rsx_vulkan_open(is_pal))
221 {
222 rsx_type = RSX_VULKAN;
223 vk_initialized = true;
224 rsx_intf_dump_init();
225 return true;
226 }
227 #endif
228
229 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
230 if ((preferred == RETRO_HW_CONTEXT_DUMMY ||
231 preferred == RETRO_HW_CONTEXT_OPENGL ||
232 preferred == RETRO_HW_CONTEXT_OPENGL_CORE)
233 && rsx_gl_open(is_pal))
234 {
235 rsx_type = RSX_OPENGL;
236 gl_initialized = true;
237 rsx_intf_dump_init();
238 return true;
239 }
240 #endif
241
242 if (preferred == RETRO_HW_CONTEXT_DUMMY)
243 MDFND_DispMessage(3, RETRO_LOG_ERROR,
244 RETRO_MESSAGE_TARGET_ALL, RETRO_MESSAGE_TYPE_NOTIFICATION,
245 "No hardware renderers could be opened. Falling back to software renderer.");
246 else
247 MDFND_DispMessage(3, RETRO_LOG_ERROR,
248 RETRO_MESSAGE_TARGET_ALL, RETRO_MESSAGE_TYPE_NOTIFICATION,
249 "Unable to find or open hardware renderer for frontend preferred hardware context. Falling back to software renderer.");
250 }
251
252 soft:
253 // rsx_soft_open(is_pal) always returns true
254 if (rsx_soft_open(is_pal))
255 {
256 rsx_type = RSX_SOFTWARE;
257 rsx_intf_dump_init();
258 return true;
259 }
260
261 /* Note: fallback will result in the software renderer running at
262 * 1x internal resolution instead of the user configured setting
263 * because of the check_variables startup sequence in libretro.cpp;
264 * this is a good thing since emulation would likely slow to a crawl
265 * if the user had >2x IR for hardware rendering and that setting was
266 * retroactively applied that to software rendering fallback
267 */
268
269 return false;
270 }
271
rsx_intf_close(void)272 void rsx_intf_close(void)
273 {
274 #if defined(RSX_DUMP)
275 rsx_dump_deinit();
276 #endif
277
278 #if defined(HAVE_VULKAN)
279 if (rsx_type != RSX_SOFTWARE && vk_initialized)
280 return;
281 #endif
282
283 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
284 if (rsx_type != RSX_SOFTWARE && gl_initialized)
285 {
286 rsx_gl_close();
287 return;
288 }
289 #endif
290 }
291
rsx_intf_refresh_variables(void)292 void rsx_intf_refresh_variables(void)
293 {
294 switch (rsx_type)
295 {
296 case RSX_SOFTWARE:
297 break;
298 case RSX_OPENGL:
299 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
300 rsx_gl_refresh_variables();
301 #endif
302 break;
303 case RSX_VULKAN:
304 #if defined(HAVE_VULKAN)
305 rsx_vulkan_refresh_variables();
306 #endif
307 break;
308 }
309 }
310
rsx_intf_prepare_frame(void)311 void rsx_intf_prepare_frame(void)
312 {
313 #ifdef RSX_DUMP
314 rsx_dump_prepare_frame();
315 #endif
316
317 switch (rsx_type)
318 {
319 case RSX_SOFTWARE:
320 break;
321 case RSX_OPENGL:
322 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
323 rsx_gl_prepare_frame();
324 #endif
325 break;
326 case RSX_VULKAN:
327 #if defined(HAVE_VULKAN)
328 rsx_vulkan_prepare_frame();
329 #endif
330 break;
331 }
332 }
333
rsx_intf_finalize_frame(const void * fb,unsigned width,unsigned height,unsigned pitch)334 void rsx_intf_finalize_frame(const void *fb, unsigned width,
335 unsigned height, unsigned pitch)
336 {
337 #ifdef RSX_DUMP
338 rsx_dump_finalize_frame();
339 #endif
340
341 switch (rsx_type)
342 {
343 case RSX_SOFTWARE:
344 video_cb(fb, width, height, pitch);
345 break;
346 case RSX_OPENGL:
347 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
348 rsx_gl_finalize_frame(fb, width, height, pitch);
349 #endif
350 break;
351 case RSX_VULKAN:
352 #if defined(HAVE_VULKAN)
353 rsx_vulkan_finalize_frame(fb, width, height, pitch);
354 #endif
355 break;
356 }
357 }
358
rsx_intf_set_tex_window(uint8_t tww,uint8_t twh,uint8_t twx,uint8_t twy)359 void rsx_intf_set_tex_window(uint8_t tww, uint8_t twh,
360 uint8_t twx, uint8_t twy)
361 {
362 #ifdef RSX_DUMP
363 rsx_dump_set_tex_window(tww, twh, twx, twy);
364 #endif
365
366 switch (rsx_type)
367 {
368 case RSX_OPENGL:
369 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
370 rsx_gl_set_tex_window(tww, twh, twx, twy);
371 #endif
372 break;
373 case RSX_VULKAN:
374 #if defined(HAVE_VULKAN)
375 rsx_vulkan_set_tex_window(tww, twh, twx, twy);
376 #endif
377 break;
378 default:
379 break;
380 }
381 }
382
rsx_intf_set_mask_setting(uint32_t mask_set_or,uint32_t mask_eval_and)383 void rsx_intf_set_mask_setting(uint32_t mask_set_or, uint32_t mask_eval_and)
384 {
385 switch (rsx_type)
386 {
387 case RSX_SOFTWARE:
388 break;
389 case RSX_OPENGL:
390 break;
391 case RSX_VULKAN:
392 /* TODO/FIXME */
393 break;
394 }
395 }
396
rsx_intf_set_draw_offset(int16_t x,int16_t y)397 void rsx_intf_set_draw_offset(int16_t x, int16_t y)
398 {
399 #ifdef RSX_DUMP
400 rsx_dump_set_draw_offset(x, y);
401 #endif
402
403 switch (rsx_type)
404 {
405 case RSX_SOFTWARE:
406 break;
407 case RSX_OPENGL:
408 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
409 rsx_gl_set_draw_offset(x, y);
410 #endif
411 break;
412 case RSX_VULKAN:
413 #if defined(HAVE_VULKAN)
414 rsx_vulkan_set_draw_offset(x, y);
415 #endif
416 break;
417 }
418 }
419
rsx_intf_set_draw_area(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1)420 void rsx_intf_set_draw_area(uint16_t x0, uint16_t y0,
421 uint16_t x1, uint16_t y1)
422 {
423 #ifdef RSX_DUMP
424 rsx_dump_set_draw_area(x0, y0, x1, y1);
425 #endif
426
427 switch (rsx_type)
428 {
429 case RSX_SOFTWARE:
430 break;
431 case RSX_OPENGL:
432 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
433 rsx_gl_set_draw_area(x0, y0, x1, y1);
434 #endif
435 break;
436 case RSX_VULKAN:
437 #if defined(HAVE_VULKAN)
438 rsx_vulkan_set_draw_area(x0, y0, x1, y1);
439 #endif
440 break;
441 }
442 }
443
rsx_intf_set_vram_framebuffer_coords(uint32_t xstart,uint32_t ystart)444 void rsx_intf_set_vram_framebuffer_coords(uint32_t xstart, uint32_t ystart)
445 {
446 #ifdef RSX_DUMP
447 rsx_dump_set_vram_framebuffer_coords(xstart, ystart);
448 #endif
449
450 switch (rsx_type)
451 {
452 case RSX_SOFTWARE:
453 break;
454 case RSX_OPENGL:
455 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
456 rsx_gl_set_vram_framebuffer_coords(xstart, ystart);
457 #endif
458 break;
459 case RSX_VULKAN:
460 #if defined(HAVE_VULKAN)
461 rsx_vulkan_set_vram_framebuffer_coords(xstart, ystart);
462 #endif
463 break;
464 }
465 }
466
rsx_intf_set_horizontal_display_range(uint16_t x1,uint16_t x2)467 void rsx_intf_set_horizontal_display_range(uint16_t x1, uint16_t x2)
468 {
469 #ifdef RSX_DUMP
470 rsx_dump_set_horizontal_display_range(x1, x2);
471 #endif
472
473 switch (rsx_type)
474 {
475 case RSX_SOFTWARE:
476 break;
477 case RSX_OPENGL:
478 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
479 rsx_gl_set_horizontal_display_range(x1, x2);
480 #endif
481 break;
482 case RSX_VULKAN:
483 #if defined(HAVE_VULKAN)
484 rsx_vulkan_set_horizontal_display_range(x1, x2);
485 #endif
486 break;
487 }
488 }
489
rsx_intf_set_vertical_display_range(uint16_t y1,uint16_t y2)490 void rsx_intf_set_vertical_display_range(uint16_t y1, uint16_t y2)
491 {
492 #ifdef RSX_DUMP
493 rsx_dump_set_vertical_display_range(y1, y2);
494 #endif
495
496 switch (rsx_type)
497 {
498 case RSX_SOFTWARE:
499 break;
500 case RSX_OPENGL:
501 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
502 rsx_gl_set_vertical_display_range(y1, y2);
503 #endif
504 break;
505 case RSX_VULKAN:
506 #if defined(HAVE_VULKAN)
507 rsx_vulkan_set_vertical_display_range(y1, y2);
508 #endif
509 break;
510 }
511 }
512
rsx_intf_set_display_mode(bool depth_24bpp,bool is_pal,bool is_480i,int width_mode)513 void rsx_intf_set_display_mode(bool depth_24bpp,
514 bool is_pal,
515 bool is_480i,
516 int width_mode)
517 {
518 #ifdef RSX_DUMP
519 rsx_dump_set_display_mode(depth_24bpp, is_pal, is_480i, width_mode);
520 #endif
521
522 // Is this check accurate for 240i timing? May need to be fixed later
523 if (currently_interlaced != is_480i)
524 {
525 currently_interlaced = is_480i;
526 interlace_setting_dirty = true;
527 }
528
529 // Also verify if this is accurate for 240i
530 if ((rsx_width_mode != width_mode) || (rsx_height_mode != (int)is_480i))
531 {
532 rsx_width_mode = width_mode;
533 rsx_height_mode = (int)is_480i;
534 aspect_ratio_dirty = true;
535 }
536
537 switch (rsx_type)
538 {
539 case RSX_SOFTWARE:
540 break;
541 case RSX_OPENGL:
542 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
543 rsx_gl_set_display_mode(depth_24bpp, is_pal, is_480i, width_mode);
544 #endif
545 break;
546 case RSX_VULKAN:
547 #if defined(HAVE_VULKAN)
548 rsx_vulkan_set_display_mode(depth_24bpp, is_pal, is_480i, width_mode);
549 #endif
550 break;
551 }
552 }
553
rsx_intf_push_triangle(float p0x,float p0y,float p0w,float p1x,float p1y,float p1w,float p2x,float p2y,float p2w,uint32_t c0,uint32_t c1,uint32_t c2,uint16_t t0x,uint16_t t0y,uint16_t t1x,uint16_t t1y,uint16_t t2x,uint16_t t2y,uint16_t min_u,uint16_t min_v,uint16_t max_u,uint16_t max_v,uint16_t texpage_x,uint16_t texpage_y,uint16_t clut_x,uint16_t clut_y,uint8_t texture_blend_mode,uint8_t depth_shift,bool dither,int blend_mode,uint32_t mask_test,uint32_t set_mask)554 void rsx_intf_push_triangle(
555 float p0x, float p0y, float p0w,
556 float p1x, float p1y, float p1w,
557 float p2x, float p2y, float p2w,
558 uint32_t c0,
559 uint32_t c1,
560 uint32_t c2,
561 uint16_t t0x, uint16_t t0y,
562 uint16_t t1x, uint16_t t1y,
563 uint16_t t2x, uint16_t t2y,
564 uint16_t min_u, uint16_t min_v,
565 uint16_t max_u, uint16_t max_v,
566 uint16_t texpage_x, uint16_t texpage_y,
567 uint16_t clut_x, uint16_t clut_y,
568 uint8_t texture_blend_mode,
569 uint8_t depth_shift,
570 bool dither,
571 int blend_mode,
572 uint32_t mask_test,
573 uint32_t set_mask)
574 {
575 #ifdef RSX_DUMP
576 const rsx_dump_vertex vertices[3] = {
577 { p0x, p0y, p0w, c0, t0x, t0y },
578 { p1x, p1y, p1w, c1, t1x, t1y },
579 { p2x, p2y, p2w, c2, t2x, t2y },
580 };
581 const rsx_render_state state = {
582 texpage_x, texpage_y, clut_x, clut_y, texture_blend_mode, depth_shift, dither, blend_mode,
583 mask_test, set_mask,
584 };
585 rsx_dump_triangle(vertices, &state);
586 #endif
587
588 switch (rsx_type)
589 {
590 case RSX_SOFTWARE:
591 break;
592 case RSX_OPENGL:
593 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
594 rsx_gl_push_triangle(p0x, p0y, p0w, p1x, p1y, p1w, p2x, p2y, p2w,
595 c0, c1, c2, t0x, t0y, t1x, t1y, t2x, t2y,
596 min_u, min_v, max_u, max_v,
597 texpage_x, texpage_y, clut_x, clut_y,
598 texture_blend_mode,
599 depth_shift,
600 dither,
601 blend_mode, mask_test != 0, set_mask != 0);
602 #endif
603 break;
604 case RSX_VULKAN:
605 #if defined(HAVE_VULKAN)
606 rsx_vulkan_push_triangle(p0x, p0y, p0w, p1x, p1y, p1w, p2x, p2y, p2w,
607 c0, c1, c2, t0x, t0y, t1x, t1y, t2x, t2y,
608 min_u, min_v, max_u, max_v,
609 texpage_x, texpage_y, clut_x, clut_y,
610 texture_blend_mode,
611 depth_shift,
612 dither,
613 blend_mode, mask_test != 0, set_mask != 0);
614 #endif
615 break;
616 }
617 }
618
rsx_intf_push_quad(float p0x,float p0y,float p0w,float p1x,float p1y,float p1w,float p2x,float p2y,float p2w,float p3x,float p3y,float p3w,uint32_t c0,uint32_t c1,uint32_t c2,uint32_t c3,uint16_t t0x,uint16_t t0y,uint16_t t1x,uint16_t t1y,uint16_t t2x,uint16_t t2y,uint16_t t3x,uint16_t t3y,uint16_t min_u,uint16_t min_v,uint16_t max_u,uint16_t max_v,uint16_t texpage_x,uint16_t texpage_y,uint16_t clut_x,uint16_t clut_y,uint8_t texture_blend_mode,uint8_t depth_shift,bool dither,int blend_mode,uint32_t mask_test,uint32_t set_mask,bool is_sprite,bool may_be_2d)619 void rsx_intf_push_quad(
620 float p0x, float p0y, float p0w,
621 float p1x, float p1y, float p1w,
622 float p2x, float p2y, float p2w,
623 float p3x, float p3y, float p3w,
624 uint32_t c0, uint32_t c1, uint32_t c2, uint32_t c3,
625 uint16_t t0x, uint16_t t0y,
626 uint16_t t1x, uint16_t t1y,
627 uint16_t t2x, uint16_t t2y,
628 uint16_t t3x, uint16_t t3y,
629 uint16_t min_u, uint16_t min_v,
630 uint16_t max_u, uint16_t max_v,
631 uint16_t texpage_x, uint16_t texpage_y,
632 uint16_t clut_x, uint16_t clut_y,
633 uint8_t texture_blend_mode,
634 uint8_t depth_shift,
635 bool dither,
636 int blend_mode,
637 uint32_t mask_test,
638 uint32_t set_mask,
639 bool is_sprite,
640 bool may_be_2d)
641 {
642 #ifdef RSX_DUMP
643 const rsx_dump_vertex vertices[4] = {
644 { p0x, p0y, p0w, c0, t0x, t0y },
645 { p1x, p1y, p1w, c1, t1x, t1y },
646 { p2x, p2y, p2w, c2, t2x, t2y },
647 { p3x, p3y, p3w, c3, t3x, t3y },
648 };
649 const rsx_render_state state = {
650 texpage_x, texpage_y, clut_x, clut_y, texture_blend_mode, depth_shift, dither, blend_mode,
651 mask_test, set_mask,
652 };
653 rsx_dump_quad(vertices, &state);
654 #endif
655
656 switch (rsx_type)
657 {
658 case RSX_SOFTWARE:
659 break;
660 case RSX_OPENGL:
661 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
662 rsx_gl_push_quad(p0x, p0y, p0w, p1x, p1y, p1w, p2x, p2y, p2w, p3x, p3y, p3w,
663 c0, c1, c2, c3,
664 t0x, t0y, t1x, t1y, t2x, t2y, t3x, t3y,
665 min_u, min_v, max_u, max_v,
666 texpage_x, texpage_y, clut_x, clut_y,
667 texture_blend_mode,
668 depth_shift,
669 dither,
670 blend_mode, mask_test != 0, set_mask != 0);
671 #endif
672 break;
673 case RSX_VULKAN:
674 #if defined(HAVE_VULKAN)
675 rsx_vulkan_push_quad(p0x, p0y, p0w, p1x, p1y, p1w, p2x, p2y, p2w, p3x, p3y, p3w,
676 c0, c1, c2, c3,
677 t0x, t0y, t1x, t1y, t2x, t2y, t3x, t3y,
678 min_u, min_v, max_u, max_v,
679 texpage_x, texpage_y, clut_x, clut_y,
680 texture_blend_mode,
681 depth_shift,
682 dither,
683 blend_mode, mask_test != 0, set_mask != 0, is_sprite, may_be_2d);
684 #endif
685 break;
686 }
687 }
688
rsx_intf_push_line(int16_t p0x,int16_t p0y,int16_t p1x,int16_t p1y,uint32_t c0,uint32_t c1,bool dither,int blend_mode,uint32_t mask_test,uint32_t set_mask)689 void rsx_intf_push_line(int16_t p0x, int16_t p0y,
690 int16_t p1x, int16_t p1y,
691 uint32_t c0, uint32_t c1,
692 bool dither,
693 int blend_mode,
694 uint32_t mask_test,
695 uint32_t set_mask)
696 {
697 #ifdef RSX_DUMP
698 const rsx_dump_line_data line = {
699 p0x, p0y, p1x, p1y, c0, c1, dither, blend_mode,
700 mask_test != 0, set_mask != 0,
701 };
702 rsx_dump_line(&line);
703 #endif
704
705 switch (rsx_type)
706 {
707 case RSX_SOFTWARE:
708 break;
709 case RSX_OPENGL:
710 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
711 rsx_gl_push_line(p0x, p0y, p1x, p1y, c0, c1, dither, blend_mode, mask_test != 0, set_mask != 0);
712 #endif
713 break;
714 case RSX_VULKAN:
715 #if defined(HAVE_VULKAN)
716 rsx_vulkan_push_line(p0x, p0y, p1x, p1y, c0, c1, dither, blend_mode, mask_test != 0, set_mask != 0);
717 #endif
718 break;
719 }
720 }
721
rsx_intf_read_vram(uint16_t x,uint16_t y,uint16_t w,uint16_t h,uint16_t * vram)722 bool rsx_intf_read_vram(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t *vram)
723 {
724 switch (rsx_type)
725 {
726 case RSX_VULKAN:
727 #if defined(HAVE_VULKAN)
728 return rsx_vulkan_read_vram(x, y, w, h, vram);
729 #endif
730 break;
731 default:
732 break;
733 }
734
735 return false;
736 }
737
rsx_intf_load_image(uint16_t x,uint16_t y,uint16_t w,uint16_t h,uint16_t * vram,uint32_t mask_test,uint32_t set_mask)738 void rsx_intf_load_image(uint16_t x, uint16_t y,
739 uint16_t w, uint16_t h,
740 uint16_t *vram, uint32_t mask_test, uint32_t set_mask)
741 {
742 #ifdef RSX_DUMP
743 rsx_dump_load_image(x, y, w, h, vram, mask_test != 0, set_mask != 0);
744 #endif
745
746 switch (rsx_type)
747 {
748 case RSX_SOFTWARE:
749 break;
750 case RSX_OPENGL:
751 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
752 rsx_gl_load_image(x, y, w, h, vram, mask_test, set_mask);
753 #endif
754 break;
755 case RSX_VULKAN:
756 #if defined(HAVE_VULKAN)
757 rsx_vulkan_load_image(x, y, w, h, vram, mask_test, set_mask);
758 #endif
759 break;
760 }
761 }
762
rsx_intf_fill_rect(uint32_t color,uint16_t x,uint16_t y,uint16_t w,uint16_t h)763 void rsx_intf_fill_rect(uint32_t color,
764 uint16_t x, uint16_t y,
765 uint16_t w, uint16_t h)
766 {
767 #ifdef RSX_DUMP
768 rsx_dump_fill_rect(color, x, y, w, h);
769 #endif
770
771 switch (rsx_type)
772 {
773 case RSX_SOFTWARE:
774 break;
775 case RSX_OPENGL:
776 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
777 rsx_gl_fill_rect(color, x, y, w, h);
778 #endif
779 break;
780 case RSX_VULKAN:
781 #if defined(HAVE_VULKAN)
782 rsx_vulkan_fill_rect(color, x, y, w, h);
783 #endif
784 break;
785 }
786 }
787
rsx_intf_copy_rect(uint16_t src_x,uint16_t src_y,uint16_t dst_x,uint16_t dst_y,uint16_t w,uint16_t h,uint32_t mask_test,uint32_t set_mask)788 void rsx_intf_copy_rect(uint16_t src_x, uint16_t src_y,
789 uint16_t dst_x, uint16_t dst_y,
790 uint16_t w, uint16_t h,
791 uint32_t mask_test, uint32_t set_mask)
792 {
793 #ifdef RSX_DUMP
794 rsx_dump_copy_rect(src_x, src_y, dst_x, dst_y, w, h, mask_test != 0, set_mask != 0);
795 #endif
796
797 switch (rsx_type)
798 {
799 case RSX_SOFTWARE:
800 break;
801 case RSX_OPENGL:
802 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
803 rsx_gl_copy_rect(src_x, src_y, dst_x, dst_y,
804 w, h, mask_test, set_mask);
805 #endif
806 break;
807 case RSX_VULKAN:
808 #if defined(HAVE_VULKAN)
809 rsx_vulkan_copy_rect(src_x, src_y, dst_x, dst_y, w, h, mask_test, set_mask);
810 #endif
811 break;
812 }
813 }
814
rsx_intf_has_software_renderer(void)815 bool rsx_intf_has_software_renderer(void)
816 {
817 switch (rsx_type)
818 {
819 case RSX_SOFTWARE:
820 return true;
821 case RSX_OPENGL:
822 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
823 return rsx_gl_has_software_renderer();
824 #endif
825 break;
826 case RSX_VULKAN:
827 #if defined(HAVE_VULKAN)
828 return rsx_vulkan_has_software_renderer();
829 #else
830 break;
831 #endif
832 }
833
834 return false;
835 }
836
rsx_intf_toggle_display(bool status)837 void rsx_intf_toggle_display(bool status)
838 {
839 #ifdef RSX_DUMP
840 rsx_dump_toggle_display(status);
841 #endif
842
843 switch (rsx_type)
844 {
845 case RSX_SOFTWARE:
846 break;
847 case RSX_OPENGL:
848 #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
849 rsx_gl_toggle_display(status);
850 #endif
851 break;
852 case RSX_VULKAN:
853 #if defined(HAVE_VULKAN)
854 rsx_vulkan_toggle_display(status);
855 #endif
856 break;
857 }
858 }
859
rsx_common_get_timing_fps(void)860 double rsx_common_get_timing_fps(void)
861 {
862 bool pal_timings = content_is_pal && !fast_pal;
863
864 if (core_timing_fps_mode == FORCE_PROGRESSIVE_TIMING)
865 return (pal_timings ? FPS_PAL_NONINTERLACED : FPS_NTSC_NONINTERLACED);
866
867 else if (core_timing_fps_mode == FORCE_INTERLACED_TIMING)
868 return (pal_timings ? FPS_PAL_INTERLACED : FPS_NTSC_INTERLACED);
869
870 //else AUTO_TOGGLE_TIMING
871 return (pal_timings ?
872 (currently_interlaced ? FPS_PAL_INTERLACED : FPS_PAL_NONINTERLACED) :
873 (currently_interlaced ? FPS_NTSC_INTERLACED : FPS_NTSC_NONINTERLACED));
874 }
875
876
rsx_common_get_aspect_ratio(bool pal_content,bool crop_overscan,int first_visible_scanline,int last_visible_scanline,int aspect_ratio_setting,bool vram_override,bool widescreen_override,int widescreen_hack_aspect_ratio_setting)877 float rsx_common_get_aspect_ratio(bool pal_content, bool crop_overscan,
878 int first_visible_scanline, int last_visible_scanline,
879 int aspect_ratio_setting, bool vram_override, bool widescreen_override,
880 int widescreen_hack_aspect_ratio_setting)
881 {
882 // Current assumptions
883 // A fixed percentage of width is cropped when crop_overscan is true
884 // aspect_ratio_setting is one of the following:
885 // 0 - Corrected
886 // 1 - Uncorrected (1:1 PAR)
887 // 2 - Force 4:3 (traditionally what Beetle PSX has done prior to adding in this setting)
888 // 3 - Force NTSC (get corrected NTSC aspect ratio even with PAL games)
889
890 // Aspect ratio overrides - VRAM and widescreen take precedence
891
892 if (vram_override)
893 return 2.0 / 1.0;
894
895 if (widescreen_override)
896 switch(widescreen_hack_aspect_ratio_setting)
897 {
898 case 0:
899 return (16.0 / 10.0);
900 case 1:
901 return (16.0 / 9.0);
902 case 2:
903 return (/*21.0 / 9.0*/ 64.0 / 27.0);
904 case 3:
905 return (32.0 / 9.0);
906 }
907
908 float ar = (4.0 / 3.0);
909
910 if (aspect_ratio_setting == 0) // Corrected
911 {
912 // Calculate horizontal scaling in terms of gpu clock cycles
913 ar *= (crop_overscan ? (2560.0 / 2800.0) : 1.0);
914
915 // Calculate vertical scaling in terms of visible scanline count
916 int num_vis_scanlines = last_visible_scanline - first_visible_scanline + 1;
917 ar *= (pal_content ? (288.0 / num_vis_scanlines) : (240.0 / num_vis_scanlines));
918
919 return ar;
920 }
921 else if (aspect_ratio_setting == 1) // Uncorrected
922 {
923 int width_base = 0;
924 switch (rsx_width_mode)
925 {
926 case WIDTH_MODE_256:
927 width_base = crop_overscan ? 256 : 280;
928 break;
929 case WIDTH_MODE_320:
930 width_base = crop_overscan ? 320 : 350;
931 break;
932 case WIDTH_MODE_512:
933 width_base = crop_overscan ? 512 : 560;
934 break;
935 case WIDTH_MODE_640:
936 width_base = crop_overscan ? 640 : 700;
937 break;
938 case WIDTH_MODE_368:
939 // Probably slightly off because of rounding, see libretro.cpp comments
940 width_base = crop_overscan ? 366 : 400;
941 break;
942 }
943
944 double height_base = (last_visible_scanline - first_visible_scanline + 1) *
945 (rsx_height_mode == HEIGHT_MODE_480 ? 2.0 : 1.0);
946
947 // Calculate aspect ratio as quotient of raw native framebuffer width and height
948 return width_base / height_base;
949 }
950 else if (aspect_ratio_setting == 3) // Force NTSC
951 {
952 ar *= (crop_overscan ? (2560.0 / 2800.0) : 1.0);
953
954 int num_vis_scanlines = last_visible_scanline - first_visible_scanline + 1;
955 ar *= (240.0 / num_vis_scanlines);
956
957 return ar;
958 }
959
960 return ar; // 4:3
961 }
962