From 1cececac18863150cacf2b05e1b2ca2aea117a14 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 28 Mar 2013 01:11:32 +0100 Subject: [PATCH] Add get_proc_address. Render something "real" in GL. --- driver.c | 12 +++ driver.h | 2 + dynamic.c | 1 + gfx/gl.c | 12 ++- gfx/thread_wrapper.c | 1 + libretro-test-gl/libretro-test.c | 151 ++++++++++++++++++++++++++++--- libretro.h | 5 + 7 files changed, 164 insertions(+), 20 deletions(-) diff --git a/driver.c b/driver.c index afeaa146cb..c06bf0920e 100644 --- a/driver.c +++ b/driver.c @@ -280,6 +280,14 @@ uintptr_t driver_get_current_framebuffer(void) return 0; } +retro_proc_address_t driver_get_proc_address(const char *sym) +{ + if (driver.video_poke && driver.video_poke->get_proc_address) + return driver.video_poke->get_proc_address(driver.video_data, sym); + else + return NULL; +} + // Only called once on init and deinit. // Video and input drivers need to be active (owned) // before retroarch core starts. @@ -332,6 +340,10 @@ void init_drivers(void) adjust_system_rates(); init_video_input(); + + if (g_extern.system.hw_render_callback.context_reset) + g_extern.system.hw_render_callback.context_reset(); + init_audio(); } diff --git a/driver.h b/driver.h index 850b26ff42..495fd9f004 100644 --- a/driver.h +++ b/driver.h @@ -324,6 +324,7 @@ typedef struct video_poke_interface void (*set_fbo_state)(void *data, unsigned state); unsigned (*get_fbo_state)(void *data); uintptr_t (*get_current_framebuffer)(void *data); + retro_proc_address_t (*get_proc_address)(void *data, const char *sym); #endif void (*set_aspect_ratio)(void *data, unsigned aspectratio_index); void (*apply_state_changes)(void *data); @@ -449,6 +450,7 @@ void driver_set_monitor_refresh_rate(float hz); // Used by RETRO_ENVIRONMENT_SET_HW_RENDER. uintptr_t driver_get_current_framebuffer(void); +retro_proc_address_t driver_get_proc_address(const char *sym); extern driver_t driver; diff --git a/dynamic.c b/dynamic.c index 4d2ede5512..b09644577b 100644 --- a/dynamic.c +++ b/dynamic.c @@ -561,6 +561,7 @@ static bool environment_cb(unsigned cmd, void *data) 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; + cb->get_proc_address = driver_get_proc_address; memcpy(&g_extern.system.hw_render_callback, cb, sizeof(*cb)); break; } diff --git a/gfx/gl.c b/gfx/gl.c index 2e41e06733..0c7699fcc7 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -1932,11 +1932,6 @@ 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; } @@ -2375,6 +2370,12 @@ 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]; } + +static retro_proc_address_t gl_get_proc_address(void *data, const char *sym) +{ + gl_t *gl = (gl_t*)data; + return gl->ctx_driver->get_proc_address(sym); +} #endif static void gl_set_aspect_ratio(void *data, unsigned aspectratio_index) @@ -2434,6 +2435,7 @@ static const video_poke_interface_t gl_poke_interface = { gl_set_fbo_state, gl_get_fbo_state, gl_get_current_framebuffer, + gl_get_proc_address, #endif gl_set_aspect_ratio, gl_apply_state_changes, diff --git a/gfx/thread_wrapper.c b/gfx/thread_wrapper.c index 7e02400008..6e598be4ef 100644 --- a/gfx/thread_wrapper.c +++ b/gfx/thread_wrapper.c @@ -679,6 +679,7 @@ static const video_poke_interface_t thread_poke = { thread_set_fbo_state, thread_get_fbo_state, NULL, + NULL, #endif thread_set_aspect_ratio, thread_apply_state_changes, diff --git a/libretro-test-gl/libretro-test.c b/libretro-test-gl/libretro-test.c index 581b14529b..be1feab5e9 100644 --- a/libretro-test-gl/libretro-test.c +++ b/libretro-test-gl/libretro-test.c @@ -5,20 +5,118 @@ #include #include #include +#define GL_GLEXT_PROTOTYPES #include -static uint16_t *frame_buf; +static PFNGLCREATEPROGRAMPROC pglCreateProgram; +static PFNGLCREATESHADERPROC pglCreateShader; +static PFNGLCREATESHADERPROC pglCompileShader; +static PFNGLCREATESHADERPROC pglUseProgram; +static PFNGLSHADERSOURCEPROC pglShaderSource; +static PFNGLATTACHSHADERPROC pglAttachShader; +static PFNGLLINKPROGRAMPROC pglLinkProgram; +static PFNGLBINDFRAMEBUFFERPROC pglBindFramebuffer; +static PFNGLGETUNIFORMLOCATIONPROC pglGetUniformLocation; +static PFNGLUNIFORMMATRIX4FVPROC pglUniformMatrix4fv; +static PFNGLGETATTRIBLOCATIONPROC pglGetAttribLocation; +static PFNGLVERTEXATTRIBPOINTERPROC pglVertexAttribPointer; +static PFNGLENABLEVERTEXATTRIBARRAYPROC pglEnableVertexAttribArray; +static PFNGLDISABLEVERTEXATTRIBARRAYPROC pglDisableVertexAttribArray; + +static struct retro_hw_render_callback hw_render; + +struct gl_proc_map +{ + void *proc; + const char *sym; +}; + +#define PROC_BIND(name) { &(pgl##name), "gl" #name } +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +static const struct gl_proc_map proc_map[] = { + PROC_BIND(CreateProgram), + PROC_BIND(CreateShader), + PROC_BIND(CompileShader), + PROC_BIND(UseProgram), + PROC_BIND(ShaderSource), + PROC_BIND(AttachShader), + PROC_BIND(LinkProgram), + PROC_BIND(BindFramebuffer), + PROC_BIND(GetUniformLocation), + PROC_BIND(GetAttribLocation), + PROC_BIND(UniformMatrix4fv), + PROC_BIND(VertexAttribPointer), + PROC_BIND(EnableVertexAttribArray), + PROC_BIND(DisableVertexAttribArray), +}; + +static void init_gl_proc(void) +{ + for (unsigned i = 0; i < ARRAY_SIZE(proc_map); i++) + { + retro_proc_address_t proc = hw_render.get_proc_address(proc_map[i].sym); + if (!proc) + fprintf(stderr, "Symbol %s not found!\n", proc_map[i].sym); + memcpy(proc_map[i].proc, &proc, sizeof(proc)); + } +} + +static GLuint prog; + +static const GLfloat vertex[] = { + 0.0, 0.0, + 1.0, 0.0, + 0.0, 1.0, + 1.0, 1.0, +}; + +static const GLfloat color[] = { + 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 0.0, 1.0, + 0.0, 1.0, 1.0, 1.0, + 1.0, 0.0, 1.0, 1.0, +}; + + +static const char *vertex_shader[] = { + "uniform mat4 uMVP;", + "attribute vec2 aVertex;", + "attribute vec4 aColor;", + "varying vec4 color;", + "void main() {", + " gl_Position = uMVP * vec4(aVertex, 0.0, 1.0);", + " color = aColor;", + "}", +}; + +static const char *fragment_shader[] = { + "varying vec4 color;", + "void main() {", + " gl_FragColor = color;", + "}", +}; + +static void compile_program(void) +{ + prog = pglCreateProgram(); + GLuint vert = pglCreateShader(GL_VERTEX_SHADER); + GLuint frag = pglCreateShader(GL_FRAGMENT_SHADER); + + pglShaderSource(vert, ARRAY_SIZE(vertex_shader), vertex_shader, 0); + pglShaderSource(frag, ARRAY_SIZE(fragment_shader), fragment_shader, 0); + pglCompileShader(vert); + pglCompileShader(frag); + + pglAttachShader(prog, vert); + pglAttachShader(prog, frag); + pglLinkProgram(prog); +} 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) { @@ -93,24 +191,47 @@ 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()); + + pglBindFramebuffer(GL_FRAMEBUFFER, hw_render.get_current_framebuffer()); + glClearColor(0.3, 0.4, 0.5, 1.0); 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); + + pglUseProgram(prog); + + int loc = pglGetUniformLocation(prog, "uMVP"); + static const GLfloat identity[] = { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, + }; + + pglUniformMatrix4fv(loc, 1, GL_FALSE, identity); + + int vloc = pglGetAttribLocation(prog, "aVertex"); + pglVertexAttribPointer(vloc, 2, GL_FLOAT, GL_FALSE, 0, vertex); + pglEnableVertexAttribArray(vloc); + int cloc = pglGetAttribLocation(prog, "aColor"); + pglVertexAttribPointer(cloc, 4, GL_FLOAT, GL_FALSE, 0, color); + pglEnableVertexAttribArray(cloc); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + pglUseProgram(0); + pglDisableVertexAttribArray(vloc); + pglDisableVertexAttribArray(cloc); + video_cb(RETRO_HW_FRAME_BUFFER_VALID, 320, 240, 0); } - static void context_reset(void) { fprintf(stderr, "Context reset!\n"); + init_gl_proc(); + compile_program(); } bool retro_load_game(const struct retro_game_info *info) diff --git a/libretro.h b/libretro.h index 47e9d56dac..048bed8fbe 100755 --- a/libretro.h +++ b/libretro.h @@ -444,6 +444,10 @@ 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); +// Get a symbol from HW context. +typedef void (*retro_proc_address_t)(void); +typedef retro_proc_address_t (*retro_hw_get_proc_address_t)(const char *sym); + enum retro_hw_context_type { RETRO_HW_CONTEXT_NONE = 0, @@ -457,6 +461,7 @@ 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. + retro_hw_get_proc_address_t get_proc_address; // Set by frontend. }; // Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK. Called by the frontend in response to keyboard events.