mirror of
https://github.com/libretro/RetroArch
synced 2025-02-27 18:41:01 +00:00
Add initial GL direct rendering test.
This commit is contained in:
parent
b8178a60eb
commit
af40f3e9b8
10
driver.c
10
driver.c
@ -270,6 +270,16 @@ void driver_set_monitor_refresh_rate(float hz)
|
||||
|
||||
}
|
||||
|
||||
uintptr_t driver_get_current_framebuffer(void)
|
||||
{
|
||||
#ifdef HAVE_FBO
|
||||
if (driver.video_poke && driver.video_poke->get_current_framebuffer)
|
||||
return driver.video_poke->get_current_framebuffer(driver.video_data);
|
||||
else
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Only called once on init and deinit.
|
||||
// Video and input drivers need to be active (owned)
|
||||
// before retroarch core starts.
|
||||
|
4
driver.h
4
driver.h
@ -323,6 +323,7 @@ typedef struct video_poke_interface
|
||||
#ifdef HAVE_FBO
|
||||
void (*set_fbo_state)(void *data, unsigned state);
|
||||
unsigned (*get_fbo_state)(void *data);
|
||||
uintptr_t (*get_current_framebuffer)(void *data);
|
||||
#endif
|
||||
void (*set_aspect_ratio)(void *data, unsigned aspectratio_index);
|
||||
void (*apply_state_changes)(void *data);
|
||||
@ -446,6 +447,9 @@ void uninit_audio(void);
|
||||
|
||||
void driver_set_monitor_refresh_rate(float hz);
|
||||
|
||||
// Used by RETRO_ENVIRONMENT_SET_HW_RENDER.
|
||||
uintptr_t driver_get_current_framebuffer(void);
|
||||
|
||||
extern driver_t driver;
|
||||
|
||||
//////////////////////////////////////////////// Backends
|
||||
|
@ -556,6 +556,15 @@ static bool environment_cb(unsigned cmd, void *data)
|
||||
g_extern.system.disk_control = *(const struct retro_disk_control_callback*)data;
|
||||
break;
|
||||
|
||||
case RETRO_ENVIRONMENT_SET_HW_RENDER:
|
||||
{
|
||||
RARCH_LOG("Environ SET_HW_RENDER.\n");
|
||||
struct retro_hw_render_callback *cb = (struct retro_hw_render_callback*)data;
|
||||
cb->get_current_framebuffer = driver_get_current_framebuffer;
|
||||
memcpy(&g_extern.system.hw_render_callback, cb, sizeof(*cb));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd);
|
||||
return false;
|
||||
|
@ -392,6 +392,7 @@ struct global
|
||||
retro_keyboard_event_t key_event;
|
||||
|
||||
struct retro_disk_control_callback disk_control;
|
||||
struct retro_hw_render_callback hw_render_callback;
|
||||
} system;
|
||||
|
||||
struct
|
||||
|
103
gfx/gl.c
103
gfx/gl.c
@ -699,6 +699,27 @@ void gl_init_fbo(void *data, unsigned width, unsigned height)
|
||||
|
||||
gl->fbo_inited = true;
|
||||
}
|
||||
|
||||
void gl_init_hw_render(gl_t *gl, unsigned width, unsigned height)
|
||||
{
|
||||
RARCH_LOG("[GL]: Initializing HW render (%u x %u).\n", width, height);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
pglGenFramebuffers(TEXTURES, gl->hw_render_fbo);
|
||||
|
||||
for (unsigned i = 0; i < TEXTURES; i++)
|
||||
{
|
||||
pglBindFramebuffer(GL_FRAMEBUFFER, gl->hw_render_fbo[i]);
|
||||
pglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl->texture[i], 0);
|
||||
GLenum status = pglCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE)
|
||||
RARCH_ERR("[GL]: Failed to create HW render FBO.\n");
|
||||
}
|
||||
|
||||
pglBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
gl->hw_render_fbo_init = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void gl_set_projection(void *data, struct gl_ortho *ortho, bool allow_rotate)
|
||||
@ -977,7 +998,7 @@ static void gl_update_resize(void *data)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void gl_update_input_size(void *data, unsigned width, unsigned height, unsigned pitch)
|
||||
static void gl_update_input_size(void *data, unsigned width, unsigned height, unsigned pitch, bool clear)
|
||||
{
|
||||
gl_t *gl = (gl_t*)data;
|
||||
// Res change. Need to clear out texture.
|
||||
@ -986,18 +1007,21 @@ static void gl_update_input_size(void *data, unsigned width, unsigned height, un
|
||||
gl->last_width[gl->tex_index] = width;
|
||||
gl->last_height[gl->tex_index] = height;
|
||||
|
||||
if (clear)
|
||||
{
|
||||
#if defined(HAVE_PSGL)
|
||||
glBufferSubData(GL_TEXTURE_REFERENCE_BUFFER_SCE,
|
||||
gl->tex_w * gl->tex_h * gl->tex_index * gl->base_size,
|
||||
gl->tex_w * gl->tex_h * gl->base_size,
|
||||
gl->empty_buf);
|
||||
glBufferSubData(GL_TEXTURE_REFERENCE_BUFFER_SCE,
|
||||
gl->tex_w * gl->tex_h * gl->tex_index * gl->base_size,
|
||||
gl->tex_w * gl->tex_h * gl->base_size,
|
||||
gl->empty_buf);
|
||||
#else
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(width * sizeof(uint32_t)));
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(width * sizeof(uint32_t)));
|
||||
|
||||
glTexSubImage2D(GL_TEXTURE_2D,
|
||||
0, 0, 0, gl->tex_w, gl->tex_h, gl->texture_type,
|
||||
gl->texture_fmt, gl->empty_buf);
|
||||
glTexSubImage2D(GL_TEXTURE_2D,
|
||||
0, 0, 0, gl->tex_w, gl->tex_h, gl->texture_type,
|
||||
gl->texture_fmt, gl->empty_buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
GLfloat xamt = (GLfloat)width / gl->tex_w;
|
||||
GLfloat yamt = (GLfloat)height / gl->tex_h;
|
||||
@ -1360,16 +1384,36 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei
|
||||
gl->tex_index = (gl->tex_index + 1) & TEXTURES_MASK;
|
||||
glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
|
||||
|
||||
gl_update_input_size(gl, width, height, pitch);
|
||||
#ifdef HAVE_FBO
|
||||
// Data is already on GPU :) Have to reset some state however incase core changed it.
|
||||
if (gl->hw_render_fbo_init)
|
||||
{
|
||||
gl_update_input_size(gl, width, height, pitch, false);
|
||||
#ifndef HAVE_OPENGLES
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
#endif
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_DITHER);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
RARCH_PERFORMANCE_INIT(copy_frame);
|
||||
RARCH_PERFORMANCE_START(copy_frame);
|
||||
gl_copy_frame(gl, frame, width, height, pitch);
|
||||
RARCH_PERFORMANCE_STOP(copy_frame);
|
||||
if (!gl->fbo_inited)
|
||||
pglBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
gl_set_viewport(gl, gl->win_width, gl->win_height, false, true);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
gl_update_input_size(gl, width, height, pitch, true);
|
||||
RARCH_PERFORMANCE_INIT(copy_frame);
|
||||
RARCH_PERFORMANCE_START(copy_frame);
|
||||
gl_copy_frame(gl, frame, width, height, pitch);
|
||||
RARCH_PERFORMANCE_STOP(copy_frame);
|
||||
|
||||
#ifdef IOS // Apparently the viewport is lost each frame, thanks apple.
|
||||
gl_set_viewport(gl, gl->win_width, gl->win_height, false, true);
|
||||
gl_set_viewport(gl, gl->win_width, gl->win_height, false, true);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
|
||||
@ -1514,6 +1558,10 @@ static void gl_free(void *data)
|
||||
|
||||
#ifdef HAVE_FBO
|
||||
gl_deinit_fbo(gl);
|
||||
|
||||
if (gl->hw_render_fbo_init)
|
||||
pglDeleteFramebuffers(TEXTURES, gl->hw_render_fbo);
|
||||
gl->hw_render_fbo_init = false;
|
||||
#endif
|
||||
|
||||
context_destroy_func();
|
||||
@ -1814,11 +1862,6 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo
|
||||
gl->tex_w = RARCH_SCALE_BASE * video->input_scale;
|
||||
gl->tex_h = RARCH_SCALE_BASE * video->input_scale;
|
||||
|
||||
#ifdef HAVE_FBO
|
||||
// Set up render to texture.
|
||||
gl_init_fbo(gl, gl->tex_w, gl->tex_h);
|
||||
#endif
|
||||
|
||||
gl->keep_aspect = video->force_aspect;
|
||||
|
||||
// Apparently need to set viewport for passes when we aren't using FBOs.
|
||||
@ -1863,6 +1906,14 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo
|
||||
gl_init_textures(gl, video);
|
||||
gl_init_textures_data(gl);
|
||||
|
||||
#ifdef HAVE_FBO
|
||||
// Set up render to texture.
|
||||
gl_init_fbo(gl, gl->tex_w, gl->tex_h);
|
||||
|
||||
if (g_extern.system.hw_render_callback.context_type == RETRO_HW_CONTEXT_OPENGL)
|
||||
gl_init_hw_render(gl, gl->tex_w, gl->tex_h);
|
||||
#endif
|
||||
|
||||
if (input && input_data)
|
||||
context_input_driver_func(input, input_data);
|
||||
|
||||
@ -1881,6 +1932,11 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_FBO
|
||||
if (gl->hw_render_fbo_init)
|
||||
g_extern.system.hw_render_callback.context_reset();
|
||||
#endif
|
||||
|
||||
return gl;
|
||||
}
|
||||
|
||||
@ -2313,6 +2369,12 @@ static unsigned gl_get_fbo_state(void *data)
|
||||
gl_t *gl = (gl_t*)data;
|
||||
return gl->fbo_inited ? FBO_INIT : FBO_DEINIT;
|
||||
}
|
||||
|
||||
static uintptr_t gl_get_current_framebuffer(void *data)
|
||||
{
|
||||
gl_t *gl = (gl_t*)data;
|
||||
return gl->hw_render_fbo[(gl->tex_index + 1) & TEXTURES_MASK];
|
||||
}
|
||||
#endif
|
||||
|
||||
static void gl_set_aspect_ratio(void *data, unsigned aspectratio_index)
|
||||
@ -2371,6 +2433,7 @@ static const video_poke_interface_t gl_poke_interface = {
|
||||
#ifdef HAVE_FBO
|
||||
gl_set_fbo_state,
|
||||
gl_get_fbo_state,
|
||||
gl_get_current_framebuffer,
|
||||
#endif
|
||||
gl_set_aspect_ratio,
|
||||
gl_apply_state_changes,
|
||||
|
@ -242,6 +242,9 @@ typedef struct gl
|
||||
struct gl_fbo_scale fbo_scale[MAX_SHADERS];
|
||||
int fbo_pass;
|
||||
bool fbo_inited;
|
||||
|
||||
GLuint hw_render_fbo[TEXTURES];
|
||||
bool hw_render_fbo_init;
|
||||
#endif
|
||||
|
||||
bool should_resize;
|
||||
|
@ -678,6 +678,7 @@ static const video_poke_interface_t thread_poke = {
|
||||
#ifdef HAVE_FBO
|
||||
thread_set_fbo_state,
|
||||
thread_get_fbo_state,
|
||||
NULL,
|
||||
#endif
|
||||
thread_set_aspect_ratio,
|
||||
thread_apply_state_changes,
|
||||
|
53
libretro-test-gl/Makefile
Normal file
53
libretro-test-gl/Makefile
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
ifeq ($(platform),)
|
||||
platform = unix
|
||||
ifeq ($(shell uname -a),)
|
||||
platform = win
|
||||
else ifneq ($(findstring MINGW,$(shell uname -a)),)
|
||||
platform = win
|
||||
else ifneq ($(findstring Darwin,$(shell uname -a)),)
|
||||
platform = osx
|
||||
else ifneq ($(findstring win,$(shell uname -a)),)
|
||||
platform = win
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(platform), unix)
|
||||
TARGET := libretro.so
|
||||
fpic := -fPIC
|
||||
SHARED := -shared -Wl,--version-script=link.T -Wl,--no-undefined
|
||||
LIBS := -lGL
|
||||
else ifeq ($(platform), osx)
|
||||
TARGET := libretro.dylib
|
||||
fpic := -fPIC
|
||||
SHARED := -dynamiclib
|
||||
LIBS := -framework OpenGL
|
||||
else
|
||||
CC = gcc
|
||||
TARGET := retro.dll
|
||||
SHARED := -shared -static-libgcc -static-libstdc++ -s -Wl,--version-script=link.T -Wl,--no-undefined
|
||||
LIBS := -lopengl32
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -O0 -g
|
||||
else
|
||||
CFLAGS += -O3
|
||||
endif
|
||||
|
||||
OBJECTS := libretro-test.o
|
||||
CFLAGS += -std=gnu99 -Wall -pedantic $(fpic)
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJECTS)
|
||||
$(CC) $(fpic) $(SHARED) $(LIBS) $(INCLUDES) -o $@ $(OBJECTS) -lm
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f $(OBJECTS) $(TARGET)
|
||||
|
||||
.PHONY: clean
|
||||
|
193
libretro-test-gl/libretro-test.c
Normal file
193
libretro-test-gl/libretro-test.c
Normal file
@ -0,0 +1,193 @@
|
||||
#include "../libretro.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glext.h>
|
||||
|
||||
static uint16_t *frame_buf;
|
||||
|
||||
void retro_init(void)
|
||||
{
|
||||
frame_buf = calloc(320 * 240, sizeof(uint16_t));
|
||||
}
|
||||
|
||||
void retro_deinit(void)
|
||||
{
|
||||
free(frame_buf);
|
||||
frame_buf = NULL;
|
||||
}
|
||||
|
||||
unsigned retro_api_version(void)
|
||||
{
|
||||
return RETRO_API_VERSION;
|
||||
}
|
||||
|
||||
void retro_set_controller_port_device(unsigned port, unsigned device)
|
||||
{
|
||||
(void)port;
|
||||
(void)device;
|
||||
}
|
||||
|
||||
void retro_get_system_info(struct retro_system_info *info)
|
||||
{
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->library_name = "TestCore GL";
|
||||
info->library_version = "v1";
|
||||
info->need_fullpath = false;
|
||||
info->valid_extensions = NULL; // Anything is fine, we don't care.
|
||||
}
|
||||
|
||||
void retro_get_system_av_info(struct retro_system_av_info *info)
|
||||
{
|
||||
info->timing = (struct retro_system_timing) {
|
||||
.fps = 60.0,
|
||||
.sample_rate = 30000.0,
|
||||
};
|
||||
|
||||
info->geometry = (struct retro_game_geometry) {
|
||||
.base_width = 320,
|
||||
.base_height = 240,
|
||||
.max_width = 320,
|
||||
.max_height = 240,
|
||||
.aspect_ratio = 4.0 / 3.0,
|
||||
};
|
||||
}
|
||||
|
||||
static retro_video_refresh_t video_cb;
|
||||
static retro_audio_sample_t audio_cb;
|
||||
static retro_audio_sample_batch_t audio_batch_cb;
|
||||
static retro_environment_t environ_cb;
|
||||
static retro_input_poll_t input_poll_cb;
|
||||
static retro_input_state_t input_state_cb;
|
||||
|
||||
void retro_set_environment(retro_environment_t cb)
|
||||
{
|
||||
environ_cb = cb;
|
||||
}
|
||||
|
||||
void retro_set_audio_sample(retro_audio_sample_t cb)
|
||||
{
|
||||
audio_cb = cb;
|
||||
}
|
||||
|
||||
void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)
|
||||
{
|
||||
audio_batch_cb = cb;
|
||||
}
|
||||
|
||||
void retro_set_input_poll(retro_input_poll_t cb)
|
||||
{
|
||||
input_poll_cb = cb;
|
||||
}
|
||||
|
||||
void retro_set_input_state(retro_input_state_t cb)
|
||||
{
|
||||
input_state_cb = cb;
|
||||
}
|
||||
|
||||
void retro_set_video_refresh(retro_video_refresh_t cb)
|
||||
{
|
||||
video_cb = cb;
|
||||
}
|
||||
|
||||
static struct retro_hw_render_callback hw_render;
|
||||
|
||||
void retro_run(void)
|
||||
{
|
||||
input_poll_cb();
|
||||
static unsigned frame_count = 0;
|
||||
frame_count = (frame_count + 1) % 60;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, hw_render.get_current_framebuffer());
|
||||
glViewport(0, 0, 320, 240);
|
||||
glClearColor(frame_count / 120.0, frame_count / 60.0, frame_count / 60.0, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
video_cb(RETRO_HW_FRAME_BUFFER_VALID, 320, 240, 0);
|
||||
}
|
||||
|
||||
|
||||
static void context_reset(void)
|
||||
{
|
||||
fprintf(stderr, "Context reset!\n");
|
||||
}
|
||||
|
||||
bool retro_load_game(const struct retro_game_info *info)
|
||||
{
|
||||
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888;
|
||||
if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt))
|
||||
{
|
||||
fprintf(stderr, "XRGB8888 is not supported.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
hw_render.context_type = RETRO_HW_CONTEXT_OPENGL;
|
||||
hw_render.context_reset = context_reset;
|
||||
if (!environ_cb(RETRO_ENVIRONMENT_SET_HW_RENDER, &hw_render))
|
||||
return false;
|
||||
|
||||
(void)info;
|
||||
return true;
|
||||
}
|
||||
|
||||
void retro_unload_game(void)
|
||||
{}
|
||||
|
||||
unsigned retro_get_region(void)
|
||||
{
|
||||
return RETRO_REGION_NTSC;
|
||||
}
|
||||
|
||||
bool retro_load_game_special(unsigned type, const struct retro_game_info *info, size_t num)
|
||||
{
|
||||
(void)type;
|
||||
(void)info;
|
||||
(void)num;
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t retro_serialize_size(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool retro_serialize(void *data, size_t size)
|
||||
{
|
||||
(void)data;
|
||||
(void)size;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool retro_unserialize(const void *data, size_t size)
|
||||
{
|
||||
(void)data;
|
||||
(void)size;
|
||||
return false;
|
||||
}
|
||||
|
||||
void *retro_get_memory_data(unsigned id)
|
||||
{
|
||||
(void)id;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t retro_get_memory_size(unsigned id)
|
||||
{
|
||||
(void)id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void retro_reset(void)
|
||||
{}
|
||||
|
||||
void retro_cheat_reset(void)
|
||||
{}
|
||||
|
||||
void retro_cheat_set(unsigned index, bool enabled, const char *code)
|
||||
{
|
||||
(void)index;
|
||||
(void)enabled;
|
||||
(void)code;
|
||||
}
|
||||
|
5
libretro-test-gl/link.T
Normal file
5
libretro-test-gl/link.T
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
global: retro_*;
|
||||
local: *;
|
||||
};
|
||||
|
36
libretro.h
36
libretro.h
@ -421,8 +421,44 @@ enum retro_mod
|
||||
// Sets an interface which frontend can use to eject and insert disk images.
|
||||
// This is used for games which consist of multiple images and must be manually
|
||||
// swapped out by the user (e.g. PSX).
|
||||
#define RETRO_ENVIRONMENT_SET_HW_RENDER 0x10000
|
||||
// struct retro_hw_render_callback * --
|
||||
// NOTE: This call is currently very experimental, and should not be considered part of the public API.
|
||||
// The interface could be changed or removed at any time.
|
||||
// Sets an interface to let a libretro core render with hardware acceleration.
|
||||
// Should be called in retro_load_game().
|
||||
// If successful, libretro cores will be able to render to a frontend-provided framebuffer.
|
||||
// The size of this framebuffer will be at least as large as max_width/max_height provided in get_av_info().
|
||||
// If HW rendering is used, pass only RETRO_HW_FRAME_BUFFER_VALID or NULL to retro_video_refresh_t.
|
||||
|
||||
|
||||
// Pass this to retro_video_refresh_t if rendering to hardware.
|
||||
// Passing NULL to retro_video_refresh_t is still a frame dupe as normal.
|
||||
#define RETRO_HW_FRAME_BUFFER_VALID ((void*)-1)
|
||||
|
||||
// Invalidates the current HW context.
|
||||
// If called, all GPU resources must be reinitialized.
|
||||
// Usually called when frontend reinits video driver.
|
||||
// Also called first time video driver is initialized, allowing libretro core to init resources.
|
||||
typedef void (*retro_hw_context_reset_t)(void);
|
||||
// Gets current framebuffer which is to be rendered to. Could change every frame potentially.
|
||||
typedef uintptr_t (*retro_hw_get_current_framebuffer_t)(void);
|
||||
|
||||
enum retro_hw_context_type
|
||||
{
|
||||
RETRO_HW_CONTEXT_NONE = 0,
|
||||
RETRO_HW_CONTEXT_OPENGL,
|
||||
|
||||
RETRO_HW_CONTEXT_DUMMY = INT_MAX
|
||||
};
|
||||
|
||||
struct retro_hw_render_callback
|
||||
{
|
||||
enum retro_hw_context_type context_type; // Which API to use. Set by libretro core.
|
||||
retro_hw_context_reset_t context_reset; // Set by libretro core.
|
||||
retro_hw_get_current_framebuffer_t get_current_framebuffer; // Set by frontend.
|
||||
};
|
||||
|
||||
// Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK. Called by the frontend in response to keyboard events.
|
||||
// down is set if the key is being pressed, or false if it is being released.
|
||||
// keycode is the RETROK value of the char.
|
||||
|
Loading…
x
Reference in New Issue
Block a user