Add support for software framebuffer
authorFrancisco José García García <frangarcj@gmail.com>
Tue, 27 Sep 2016 22:44:37 +0000 (00:44 +0200)
committerFrancisco José García García <frangarcj@gmail.com>
Tue, 27 Sep 2016 22:44:37 +0000 (00:44 +0200)
frontend/libretro.c
frontend/libretro.h

index 81afc30..66175af 100644 (file)
@@ -47,6 +47,7 @@ static retro_audio_sample_batch_t audio_batch_cb;
 static struct retro_rumble_interface rumble;
 
 static void *vout_buf;
+static void * vout_buf_ptr;
 static int vout_width, vout_height;
 static int vout_doffs_old, vout_fb_dirty;
 static bool vout_can_dupe;
@@ -133,14 +134,14 @@ static void convert(void *buf, size_t bytes)
 
 static void vout_flip(const void *vram, int stride, int bgr24, int w, int h)
 {
-       unsigned short *dest = vout_buf;
+       unsigned short *dest = vout_buf_ptr;
        const unsigned short *src = vram;
        int dstride = vout_width, h1 = h;
        int doffs;
 
        if (vram == NULL) {
                // blanking
-               memset(vout_buf, 0, dstride * h * 2);
+               memset(vout_buf_ptr, 0, dstride * h * 2);
                goto out;
        }
 
@@ -148,7 +149,7 @@ static void vout_flip(const void *vram, int stride, int bgr24, int w, int h)
        doffs += (dstride - w) / 2 & ~1;
        if (doffs != vout_doffs_old) {
                // clear borders
-               memset(vout_buf, 0, dstride * h * 2);
+               memset(vout_buf_ptr, 0, dstride * h * 2);
                vout_doffs_old = doffs;
        }
        dest += doffs;
@@ -171,7 +172,7 @@ static void vout_flip(const void *vram, int stride, int bgr24, int w, int h)
 
 out:
 #ifndef FRONTEND_SUPPORTS_RGB565
-       convert(vout_buf, vout_width * vout_height * 2);
+       convert(vout_buf_ptr, vout_width * vout_height * 2);
 #endif
        vout_fb_dirty = 1;
        pl_rearmed_cbs.flip_cnt++;
@@ -1483,8 +1484,21 @@ void retro_run(void)
 
        stop = 0;
        psxCpu->Execute();
+  
+  struct retro_framebuffer fb = {0};
+  
+  fb.width           = vout_width;
+  fb.height          = vout_height;
+  fb.access_flags    = RETRO_MEMORY_ACCESS_WRITE;
+
+  vout_buf_ptr = vout_buf; 
+   
+  if (environ_cb(RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER, &fb) && fb.format == RETRO_PIXEL_FORMAT_RGB565)
+  {
+     vout_buf_ptr  = (uint16_t*)fb.data;
+  }  
 
-       video_cb((vout_fb_dirty || !vout_can_dupe || !duping_enable) ? vout_buf : NULL,
+       video_cb((vout_fb_dirty || !vout_can_dupe || !duping_enable) ? vout_buf_ptr : NULL,
                vout_width, vout_height, vout_width * 2);
        vout_fb_dirty = 0;
 }
@@ -1593,7 +1607,9 @@ void retro_init(void)
 #else
        vout_buf = malloc(VOUT_MAX_WIDTH * VOUT_MAX_HEIGHT * 2);
 #endif
-
+  
+  vout_buf_ptr = vout_buf;
+  
        if (environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir) && dir)
        {
                snprintf(Config.BiosDir, sizeof(Config.BiosDir), "%s", dir);
index 16c274a..a231548 100755 (executable)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010-2014 The RetroArch team
+/* Copyright (C) 2010-2016 The RetroArch team
  *
  * ---------------------------------------------------------------------------------------
  * The following license statement only applies to this libretro API header (libretro.h).
@@ -43,6 +43,40 @@ extern "C" {
 #endif
 #endif
 
+#ifndef RETRO_CALLCONV
+#  if defined(__GNUC__) && defined(__i386__) && !defined(__x86_64__)
+#    define RETRO_CALLCONV __attribute__((cdecl))
+#  elif defined(_MSC_VER) && defined(_M_X86) && !defined(_M_X64)
+#    define RETRO_CALLCONV __cdecl
+#  else
+#    define RETRO_CALLCONV /* all other platforms only have one calling convention each */
+#  endif
+#endif
+
+#ifndef RETRO_API
+#  if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
+#    ifdef RETRO_IMPORT_SYMBOLS
+#      ifdef __GNUC__
+#        define RETRO_API RETRO_CALLCONV __attribute__((__dllimport__))
+#      else
+#        define RETRO_API RETRO_CALLCONV __declspec(dllimport)
+#      endif
+#    else
+#      ifdef __GNUC__
+#        define RETRO_API RETRO_CALLCONV __attribute__((__dllexport__))
+#      else
+#        define RETRO_API RETRO_CALLCONV __declspec(dllexport)
+#      endif
+#    endif
+#  else
+#      if defined(__GNUC__) && __GNUC__ >= 4 && !defined(__CELLOS_LV2__)
+#        define RETRO_API RETRO_CALLCONV __attribute__((__visibility__("default")))
+#      else
+#        define RETRO_API RETRO_CALLCONV
+#      endif
+#  endif
+#endif
+
 /* Used for checking API/ABI mismatches that can break libretro 
  * implementations.
  * It is not incremented for compatible changes to the API.
@@ -165,13 +199,15 @@ extern "C" {
 #define RETRO_DEVICE_ID_ANALOG_Y         1
 
 /* Id values for MOUSE. */
-#define RETRO_DEVICE_ID_MOUSE_X          0
-#define RETRO_DEVICE_ID_MOUSE_Y          1
-#define RETRO_DEVICE_ID_MOUSE_LEFT       2
-#define RETRO_DEVICE_ID_MOUSE_RIGHT      3
-#define RETRO_DEVICE_ID_MOUSE_WHEELUP    4
-#define RETRO_DEVICE_ID_MOUSE_WHEELDOWN  5
-#define RETRO_DEVICE_ID_MOUSE_MIDDLE     6
+#define RETRO_DEVICE_ID_MOUSE_X                0
+#define RETRO_DEVICE_ID_MOUSE_Y                1
+#define RETRO_DEVICE_ID_MOUSE_LEFT             2
+#define RETRO_DEVICE_ID_MOUSE_RIGHT            3
+#define RETRO_DEVICE_ID_MOUSE_WHEELUP          4
+#define RETRO_DEVICE_ID_MOUSE_WHEELDOWN        5
+#define RETRO_DEVICE_ID_MOUSE_MIDDLE           6
+#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP    7
+#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN  8
 
 /* Id values for LIGHTGUN types. */
 #define RETRO_DEVICE_ID_LIGHTGUN_X        0
@@ -206,6 +242,8 @@ enum retro_language
    RETRO_LANGUAGE_KOREAN              =  9,
    RETRO_LANGUAGE_CHINESE_TRADITIONAL = 10,
    RETRO_LANGUAGE_CHINESE_SIMPLIFIED  = 11,
+   RETRO_LANGUAGE_ESPERANTO           = 12,
+   RETRO_LANGUAGE_POLISH              = 13,
    RETRO_LANGUAGE_LAST,
 
    /* Ensure sizeof(enum) == sizeof(int) */
@@ -693,9 +731,10 @@ enum retro_mod
                                             * location-based information from the host device,
                                             * such as current latitude / longitude.
                                             */
-#define RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY 30
+#define RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY 30 /* Old name, kept for compatibility. */
+#define RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY 30
                                            /* const char ** --
-                                            * Returns the "content" directory of the frontend.
+                                            * Returns the "core assets" directory of the frontend.
                                             * This directory can be used to store specific assets that the 
                                             * core relies upon, such as art assets,
                                             * input data, etc etc.
@@ -851,6 +890,61 @@ enum retro_mod
                                             * Returns the specified language of the frontend, if specified by the user.
                                             * It can be used by the core for localization purposes.
                                             */
+#define RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER (40 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* struct retro_framebuffer * --
+                                            * Returns a preallocated framebuffer which the core can use for rendering
+                                            * the frame into when not using SET_HW_RENDER.
+                                            * The framebuffer returned from this call must not be used
+                                            * after the current call to retro_run() returns.
+                                            *
+                                            * The goal of this call is to allow zero-copy behavior where a core
+                                            * can render directly into video memory, avoiding extra bandwidth cost by copying
+                                            * memory from core to video memory.
+                                            *
+                                            * If this call succeeds and the core renders into it,
+                                            * the framebuffer pointer and pitch can be passed to retro_video_refresh_t.
+                                            * If the buffer from GET_CURRENT_SOFTWARE_FRAMEBUFFER is to be used,
+                                            * the core must pass the exact
+                                            * same pointer as returned by GET_CURRENT_SOFTWARE_FRAMEBUFFER;
+                                            * i.e. passing a pointer which is offset from the
+                                            * buffer is undefined. The width, height and pitch parameters
+                                            * must also match exactly to the values obtained from GET_CURRENT_SOFTWARE_FRAMEBUFFER.
+                                            *
+                                            * It is possible for a frontend to return a different pixel format
+                                            * than the one used in SET_PIXEL_FORMAT. This can happen if the frontend
+                                            * needs to perform conversion.
+                                            *
+                                            * It is still valid for a core to render to a different buffer
+                                            * even if GET_CURRENT_SOFTWARE_FRAMEBUFFER succeeds.
+                                            *
+                                            * A frontend must make sure that the pointer obtained from this function is
+                                            * writeable (and readable).
+                                            */
+
+enum retro_hw_render_interface_type
+{
+   RETRO_HW_RENDER_INTERFACE_VULKAN = 0,
+   RETRO_HW_RENDER_INTERFACE_DUMMY = INT_MAX
+};
+
+/* Base struct. All retro_hw_render_interface_* types
+ * contain at least these fields. */
+struct retro_hw_render_interface
+{
+   enum retro_hw_render_interface_type interface_type;
+   unsigned interface_version;
+};
+#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* const struct retro_hw_render_interface ** --
+                                            * Returns an API specific rendering interface for accessing API specific data.
+                                            * Not all HW rendering APIs support or need this.
+                                            * The contents of the returned pointer is specific to the rendering API
+                                            * being used. See the various headers like libretro_vulkan.h, etc.
+                                            *
+                                            * GET_HW_RENDER_INTERFACE cannot be called before context_reset has been called.
+                                            * Similarly, after context_destroyed callback returns,
+                                            * the contents of the HW_RENDER_INTERFACE are invalidated.
+                                            */
 
 #define RETRO_MEMDESC_CONST     (1 << 0)   /* The frontend will never change this memory area once retro_load_game has returned. */
 #define RETRO_MEMDESC_BIGENDIAN (1 << 1)   /* The memory area contains big endian data. Default is little endian. */
@@ -1125,6 +1219,10 @@ struct retro_log_callback
 #define RETRO_SIMD_VFPU     (1 << 13)
 #define RETRO_SIMD_PS       (1 << 14)
 #define RETRO_SIMD_AES      (1 << 15)
+#define RETRO_SIMD_VFPV3    (1 << 16)
+#define RETRO_SIMD_VFPV4    (1 << 17)
+#define RETRO_SIMD_POPCNT   (1 << 18)
+#define RETRO_SIMD_MOVBE    (1 << 19)
 
 typedef uint64_t retro_perf_tick_t;
 typedef int64_t retro_time_t;
@@ -1464,6 +1562,9 @@ enum retro_hw_context_type
     * use the corresponding enums directly. */
    RETRO_HW_CONTEXT_OPENGLES_VERSION = 5,
 
+   /* Vulkan, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE. */
+   RETRO_HW_CONTEXT_VULKAN           = 6,
+
    RETRO_HW_CONTEXT_DUMMY = INT_MAX
 };
 
@@ -1486,23 +1587,28 @@ struct retro_hw_render_callback
     */
    retro_hw_context_reset_t context_reset;
 
-   /* Set by frontend. */
+   /* Set by frontend.
+    * TODO: This is rather obsolete. The frontend should not
+    * be providing preallocated framebuffers. */
    retro_hw_get_current_framebuffer_t get_current_framebuffer;
 
    /* Set by frontend. */
    retro_hw_get_proc_address_t get_proc_address;
 
-   /* Set if render buffers should have depth component attached. */
+   /* Set if render buffers should have depth component attached.
+    * TODO: Obsolete. */
    bool depth;
 
-   /* Set if stencil buffers should be attached. */
+   /* Set if stencil buffers should be attached.
+    * TODO: Obsolete. */
    bool stencil;
 
    /* If depth and stencil are true, a packed 24/8 buffer will be added. 
     * Only attaching stencil is invalid and will be ignored. */
 
    /* Use conventional bottom-left origin convention. If false, 
-    * standard libretro top-left origin semantics are used. */
+    * standard libretro top-left origin semantics are used.
+    * TODO: Move to GL specific interface. */
    bool bottom_left_origin;
    
    /* Major version number for core GL context or GLES 3.1+. */
@@ -1513,6 +1619,7 @@ struct retro_hw_render_callback
 
    /* If this is true, the frontend will go very far to avoid 
     * resetting context in scenarios like toggling fullscreen, etc.
+    * TODO: Obsolete? Maybe frontend should just always assume this ...
     */
    bool cache_context;
 
@@ -1779,6 +1886,36 @@ struct retro_game_info
    const char *meta;       /* String of implementation specific meta-data. */
 };
 
+#define RETRO_MEMORY_ACCESS_WRITE (1 << 0)
+   /* The core will write to the buffer provided by retro_framebuffer::data. */
+#define RETRO_MEMORY_ACCESS_READ (1 << 1)
+   /* The core will read from retro_framebuffer::data. */
+#define RETRO_MEMORY_TYPE_CACHED (1 << 0)
+   /* The memory in data is cached.
+    * If not cached, random writes and/or reading from the buffer is expected to be very slow. */
+struct retro_framebuffer
+{
+   void *data;                      /* The framebuffer which the core can render into.
+                                       Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER.
+                                       The initial contents of data are unspecified. */
+   unsigned width;                  /* The framebuffer width used by the core. Set by core. */
+   unsigned height;                 /* The framebuffer height used by the core. Set by core. */
+   size_t pitch;                    /* The number of bytes between the beginning of a scanline,
+                                       and beginning of the next scanline.
+                                       Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */
+   enum retro_pixel_format format;  /* The pixel format the core must use to render into data.
+                                       This format could differ from the format used in
+                                       SET_PIXEL_FORMAT.
+                                       Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */
+
+   unsigned access_flags;           /* How the core will access the memory in the framebuffer.
+                                       RETRO_MEMORY_ACCESS_* flags.
+                                       Set by core. */
+   unsigned memory_flags;           /* Flags telling core how the memory has been mapped.
+                                       RETRO_MEMORY_TYPE_* flags.
+                                       Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */
+};
+
 /* Callbacks */
 
 /* Environment callback. Gives implementations a way of performing 
@@ -1832,25 +1969,25 @@ typedef int16_t (*retro_input_state_t)(unsigned port, unsigned device,
  *
  * The rest of the set_* functions are guaranteed to have been called 
  * before the first call to retro_run() is made. */
-void retro_set_environment(retro_environment_t);
-void retro_set_video_refresh(retro_video_refresh_t);
-void retro_set_audio_sample(retro_audio_sample_t);
-void retro_set_audio_sample_batch(retro_audio_sample_batch_t);
-void retro_set_input_poll(retro_input_poll_t);
-void retro_set_input_state(retro_input_state_t);
+RETRO_API void retro_set_environment(retro_environment_t);
+RETRO_API void retro_set_video_refresh(retro_video_refresh_t);
+RETRO_API void retro_set_audio_sample(retro_audio_sample_t);
+RETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t);
+RETRO_API void retro_set_input_poll(retro_input_poll_t);
+RETRO_API void retro_set_input_state(retro_input_state_t);
 
 /* Library global initialization/deinitialization. */
-void retro_init(void);
-void retro_deinit(void);
+RETRO_API void retro_init(void);
+RETRO_API void retro_deinit(void);
 
 /* Must return RETRO_API_VERSION. Used to validate ABI compatibility
  * when the API is revised. */
-unsigned retro_api_version(void);
+RETRO_API unsigned retro_api_version(void);
 
 /* Gets statically known system info. Pointers provided in *info 
  * must be statically allocated.
  * Can be called at any time, even before retro_init(). */
-void retro_get_system_info(struct retro_system_info *info);
+RETRO_API void retro_get_system_info(struct retro_system_info *info);
 
 /* Gets information about system audio/video timings and geometry.
  * Can be called only after retro_load_game() has successfully completed.
@@ -1858,7 +1995,7 @@ void retro_get_system_info(struct retro_system_info *info);
  * variable if needed.
  * E.g. geom.aspect_ratio might not be initialized if core doesn't 
  * desire a particular aspect ratio. */
-void retro_get_system_av_info(struct retro_system_av_info *info);
+RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info);
 
 /* Sets device to be used for player 'port'.
  * By default, RETRO_DEVICE_JOYPAD is assumed to be plugged into all 
@@ -1868,10 +2005,10 @@ void retro_get_system_av_info(struct retro_system_av_info *info);
  * hint to the libretro core when a core cannot automatically detect the 
  * appropriate input device type on its own. It is also relevant when a 
  * core can change its behavior depending on device type. */
-void retro_set_controller_port_device(unsigned port, unsigned device);
+RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device);
 
 /* Resets the current game. */
-void retro_reset(void);
+RETRO_API void retro_reset(void);
 
 /* Runs the game for one video frame.
  * During retro_run(), input_poll callback must be called at least once.
@@ -1881,7 +2018,7 @@ void retro_reset(void);
  * a frame if GET_CAN_DUPE returns true.
  * In this case, the video callback can take a NULL argument for data.
  */
-void retro_run(void);
+RETRO_API void retro_run(void);
 
 /* Returns the amount of data the implementation requires to serialize 
  * internal state (save states).
@@ -1889,35 +2026,35 @@ void retro_run(void);
  * returned size is never allowed to be larger than a previous returned 
  * value, to ensure that the frontend can allocate a save state buffer once.
  */
-size_t retro_serialize_size(void);
+RETRO_API size_t retro_serialize_size(void);
 
 /* Serializes internal state. If failed, or size is lower than
  * retro_serialize_size(), it should return false, true otherwise. */
-bool retro_serialize(void *data, size_t size);
-bool retro_unserialize(const void *data, size_t size);
+RETRO_API bool retro_serialize(void *data, size_t size);
+RETRO_API bool retro_unserialize(const void *data, size_t size);
 
-void retro_cheat_reset(void);
-void retro_cheat_set(unsigned index, bool enabled, const char *code);
+RETRO_API void retro_cheat_reset(void);
+RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code);
 
 /* Loads a game. */
-bool retro_load_game(const struct retro_game_info *game);
+RETRO_API bool retro_load_game(const struct retro_game_info *game);
 
 /* Loads a "special" kind of game. Should not be used,
  * except in extreme cases. */
-bool retro_load_game_special(
+RETRO_API bool retro_load_game_special(
   unsigned game_type,
   const struct retro_game_info *info, size_t num_info
 );
 
 /* Unloads a currently loaded game. */
-void retro_unload_game(void);
+RETRO_API void retro_unload_game(void);
 
 /* Gets region of game. */
-unsigned retro_get_region(void);
+RETRO_API unsigned retro_get_region(void);
 
 /* Gets region of memory. */
-void *retro_get_memory_data(unsigned id);
-size_t retro_get_memory_size(unsigned id);
+RETRO_API void *retro_get_memory_data(unsigned id);
+RETRO_API size_t retro_get_memory_size(unsigned id);
 
 #ifdef __cplusplus
 }