diff --git a/dynamic.c b/dynamic.c index c577da427d..e435ed1975 100644 --- a/dynamic.c +++ b/dynamic.c @@ -1205,6 +1205,9 @@ bool rarch_environment_cb(unsigned cmd, void *data) break; } + case RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER: + return video_driver_get_current_software_framebuffer((struct retro_framebuffer*)data); + /* Private extensions for internal use, not part of libretro API. */ case RETRO_ENVIRONMENT_SET_LIBRETRO_PATH: RARCH_LOG("Environ (Private) SET_LIBRETRO_PATH.\n"); diff --git a/gfx/video_driver.c b/gfx/video_driver.c index 3d8653ae7f..58185f2ef9 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -322,6 +322,12 @@ uintptr_t video_driver_get_current_framebuffer(void) return 0; } +bool video_driver_get_current_software_framebuffer(struct retro_framebuffer *framebuffer) +{ + if (video_driver_poke && video_driver_poke->get_current_software_framebuffer) + return video_driver_poke->get_current_software_framebuffer(video_driver_data, framebuffer); + return false; +} retro_proc_address_t video_driver_get_proc_address(const char *sym) { diff --git a/gfx/video_driver.h b/gfx/video_driver.h index abab68adb6..1fe12a7e48 100644 --- a/gfx/video_driver.h +++ b/gfx/video_driver.h @@ -217,6 +217,7 @@ typedef struct video_poke_interface void (*grab_mouse_toggle)(void *data); struct video_shader *(*get_current_shader)(void *data); + bool (*get_current_software_framebuffer)(void *data, struct retro_framebuffer *framebuffer); } video_poke_interface_t; typedef struct video_viewport @@ -371,6 +372,8 @@ void *video_driver_get_ptr(bool force_nonthreaded_data); **/ uintptr_t video_driver_get_current_framebuffer(void); +bool video_driver_get_current_software_framebuffer(struct retro_framebuffer *framebuffer); + retro_proc_address_t video_driver_get_proc_address(const char *sym); bool video_driver_set_shader(enum rarch_shader_type type, diff --git a/libretro.h b/libretro.h index ddf273de2a..77a8d3f97a 100644 --- a/libretro.h +++ b/libretro.h @@ -890,6 +890,36 @@ 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). + */ #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. */ @@ -1822,6 +1852,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