From af40f3e9b8bdf7e162272b05b3095e0a223915fb Mon Sep 17 00:00:00 2001 From: Themaister Date: Wed, 27 Mar 2013 16:15:15 +0100 Subject: [PATCH 01/14] Add initial GL direct rendering test. --- driver.c | 10 ++ driver.h | 4 + dynamic.c | 9 ++ general.h | 1 + gfx/gl.c | 103 +++++++++++++---- gfx/gl_common.h | 3 + gfx/thread_wrapper.c | 1 + libretro-test-gl/Makefile | 53 +++++++++ libretro-test-gl/libretro-test.c | 193 +++++++++++++++++++++++++++++++ libretro-test-gl/link.T | 5 + libretro.h | 36 ++++++ 11 files changed, 398 insertions(+), 20 deletions(-) create mode 100644 libretro-test-gl/Makefile create mode 100644 libretro-test-gl/libretro-test.c create mode 100644 libretro-test-gl/link.T diff --git a/driver.c b/driver.c index 4450282ca6..afeaa146cb 100644 --- a/driver.c +++ b/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. diff --git a/driver.h b/driver.h index ff7228b874..850b26ff42 100644 --- a/driver.h +++ b/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 diff --git a/dynamic.c b/dynamic.c index 2bd8dcb297..4d2ede5512 100644 --- a/dynamic.c +++ b/dynamic.c @@ -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; diff --git a/general.h b/general.h index 6481daee05..29b2fca8b9 100644 --- a/general.h +++ b/general.h @@ -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 diff --git a/gfx/gl.c b/gfx/gl.c index c647755ce9..0de4969a61 100644 --- a/gfx/gl.c +++ b/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, diff --git a/gfx/gl_common.h b/gfx/gl_common.h index 6ff82cfa2e..814ba5611e 100644 --- a/gfx/gl_common.h +++ b/gfx/gl_common.h @@ -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; diff --git a/gfx/thread_wrapper.c b/gfx/thread_wrapper.c index 4688e9f6e4..7e02400008 100644 --- a/gfx/thread_wrapper.c +++ b/gfx/thread_wrapper.c @@ -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, diff --git a/libretro-test-gl/Makefile b/libretro-test-gl/Makefile new file mode 100644 index 0000000000..dd4bf79d17 --- /dev/null +++ b/libretro-test-gl/Makefile @@ -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 + diff --git a/libretro-test-gl/libretro-test.c b/libretro-test-gl/libretro-test.c new file mode 100644 index 0000000000..581b14529b --- /dev/null +++ b/libretro-test-gl/libretro-test.c @@ -0,0 +1,193 @@ +#include "../libretro.h" +#include +#include +#include +#include +#include +#include +#include + +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; +} + diff --git a/libretro-test-gl/link.T b/libretro-test-gl/link.T new file mode 100644 index 0000000000..b0c262db9e --- /dev/null +++ b/libretro-test-gl/link.T @@ -0,0 +1,5 @@ +{ + global: retro_*; + local: *; +}; + diff --git a/libretro.h b/libretro.h index 0c39e6edae..47e9d56dac 100755 --- a/libretro.h +++ b/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. From f7cab361888d6cffdd1b54f7ee029fa1cc39246c Mon Sep 17 00:00:00 2001 From: Themaister Date: Wed, 27 Mar 2013 16:22:56 +0100 Subject: [PATCH 02/14] Fix viewport when rendering to FBO. --- gfx/gl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gfx/gl.c b/gfx/gl.c index 0de4969a61..2e41e06733 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -705,7 +705,6 @@ 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++) @@ -1397,9 +1396,10 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei glClearColor(0.0f, 0.0f, 0.0f, 1.0f); if (!gl->fbo_inited) + { pglBindFramebuffer(GL_FRAMEBUFFER, 0); - - gl_set_viewport(gl, gl->win_width, gl->win_height, false, true); + gl_set_viewport(gl, gl->win_width, gl->win_height, false, true); + } } else #endif From 1cececac18863150cacf2b05e1b2ca2aea117a14 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 28 Mar 2013 01:11:32 +0100 Subject: [PATCH 03/14] 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. From 77861f5a593862ec9e061e17061796574e370fd1 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 28 Mar 2013 01:19:48 +0100 Subject: [PATCH 04/14] Render something in motion. --- gfx/gl.c | 2 ++ libretro-test-gl/libretro-test.c | 35 +++++++++++++++++++------------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/gfx/gl.c b/gfx/gl.c index 0c7699fcc7..00db5e035d 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -1392,6 +1392,7 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei glEnable(GL_TEXTURE_2D); #endif glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); glDisable(GL_DITHER); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); @@ -1881,6 +1882,7 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo #endif glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); glDisable(GL_DITHER); memcpy(gl->tex_coords, tex_coords, sizeof(tex_coords)); diff --git a/libretro-test-gl/libretro-test.c b/libretro-test-gl/libretro-test.c index be1feab5e9..5f43e6c9d2 100644 --- a/libretro-test-gl/libretro-test.c +++ b/libretro-test-gl/libretro-test.c @@ -64,10 +64,10 @@ static void init_gl_proc(void) static GLuint prog; static const GLfloat vertex[] = { - 0.0, 0.0, - 1.0, 0.0, - 0.0, 1.0, - 1.0, 1.0, + -0.5, -0.5, + 0.5, -0.5, + -0.5, 0.5, + 0.5, 0.5, }; static const GLfloat color[] = { @@ -146,10 +146,10 @@ void retro_get_system_av_info(struct retro_system_av_info *info) }; info->geometry = (struct retro_game_geometry) { - .base_width = 320, - .base_height = 240, - .max_width = 320, - .max_height = 240, + .base_width = 512, + .base_height = 512, + .max_width = 512, + .max_height = 512, .aspect_ratio = 4.0 / 3.0, }; } @@ -197,20 +197,27 @@ void retro_run(void) pglBindFramebuffer(GL_FRAMEBUFFER, hw_render.get_current_framebuffer()); glClearColor(0.3, 0.4, 0.5, 1.0); - glViewport(0, 0, 320, 240); + glViewport(0, 0, 512, 512); glClear(GL_COLOR_BUFFER_BIT); pglUseProgram(prog); int loc = pglGetUniformLocation(prog, "uMVP"); - static const GLfloat identity[] = { - 1, 0, 0, 0, - 0, 1, 0, 0, + + static unsigned frame_count; + frame_count++; + float angle = frame_count / 100.0; + float cos_angle = cos(angle); + float sin_angle = sin(angle); + + const GLfloat mvp[] = { + cos_angle, -sin_angle, 0, 0, + sin_angle, cos_angle, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, }; - pglUniformMatrix4fv(loc, 1, GL_FALSE, identity); + pglUniformMatrix4fv(loc, 1, GL_FALSE, mvp); int vloc = pglGetAttribLocation(prog, "aVertex"); pglVertexAttribPointer(vloc, 2, GL_FLOAT, GL_FALSE, 0, vertex); @@ -224,7 +231,7 @@ void retro_run(void) pglDisableVertexAttribArray(vloc); pglDisableVertexAttribArray(cloc); - video_cb(RETRO_HW_FRAME_BUFFER_VALID, 320, 240, 0); + video_cb(RETRO_HW_FRAME_BUFFER_VALID, 512, 512, 0); } static void context_reset(void) From 8783cbb010607e2fc84acf7fad63787587688806 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 28 Mar 2013 12:13:41 +0100 Subject: [PATCH 05/14] Handle GL state more carefully. --- gfx/gl.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/gfx/gl.c b/gfx/gl.c index 00db5e035d..eba64aba59 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -1388,13 +1388,6 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei 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_CULL_FACE); - glDisable(GL_DITHER); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); if (!gl->fbo_inited) { @@ -1419,6 +1412,20 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei else glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]); + // Have to reset rendering state which libretro core could easily have overridden. +#ifdef HAVE_FBO + if (gl->hw_render_fbo_init) + { +#ifndef HAVE_OPENGLES + glEnable(GL_TEXTURE_2D); +#endif + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_DITHER); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + } +#endif + struct gl_tex_info tex_info = {0}; tex_info.tex = gl->texture[gl->tex_index]; tex_info.input_size[0] = width; @@ -1485,6 +1492,23 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei RARCH_PERFORMANCE_STOP(frame_run); +#ifdef HAVE_FBO + // Reset state which could easily mess up libretro core. + if (gl->hw_render_fbo_init) + { + gl_shader_use_func(gl, 0); + glBindTexture(GL_TEXTURE_2D, 0); +#ifndef NO_GL_FF_VERTEX + pglClientActiveTexture(GL_TEXTURE1); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + pglClientActiveTexture(GL_TEXTURE0); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +#endif + } +#endif + #if defined(HAVE_RMENU) if (lifecycle_mode_state & (1ULL << MODE_MENU_DRAW)) context_rmenu_frame_func(gl); @@ -1496,7 +1520,7 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei if (gl->pbo_readback_enable) gl_pbo_async_readback(gl); #endif - + return true; } From 4bcc566afbf0228e66501924a139dc67ebbf16cf Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 28 Mar 2013 12:27:40 +0100 Subject: [PATCH 06/14] Fix some possible segfaults with HW render. --- driver.c | 6 ++++++ retroarch.c | 28 +++++++++++++++++++++++----- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/driver.c b/driver.c index c06bf0920e..34edc095aa 100644 --- a/driver.c +++ b/driver.c @@ -667,6 +667,12 @@ static void init_filter(bool rgb32) if (!*g_settings.video.filter_path) return; + if (g_extern.system.hw_render_callback.context_type) + { + RARCH_WARN("Cannot use CPU filters when hardware rendering is used.\n"); + return; + } + RARCH_LOG("Loading bSNES filter from \"%s\"\n", g_settings.video.filter_path); g_extern.filter.lib = dylib_load(g_settings.video.filter_path); if (!g_extern.filter.lib) diff --git a/retroarch.c b/retroarch.c index a2cd8ffa8a..9a9a5afd83 100644 --- a/retroarch.c +++ b/retroarch.c @@ -141,10 +141,18 @@ static void take_screenshot(void) bool ret = false; - if (g_settings.video.gpu_screenshot && driver.video->read_viewport && driver.video->viewport_info) - ret = take_screenshot_viewport(); - else if (g_extern.frame_cache.data) - ret = take_screenshot_raw(); + if (g_extern.frame_cache.data) + { + if ((g_settings.video.gpu_screenshot || + (g_extern.frame_cache.data == RETRO_HW_FRAME_BUFFER_VALID)) && + driver.video->read_viewport && + driver.video->viewport_info) + ret = take_screenshot_viewport(); + else if (g_extern.frame_cache.data && (g_extern.frame_cache.data != RETRO_HW_FRAME_BUFFER_VALID)) + ret = take_screenshot_raw(); + else + RARCH_ERR("Cannot take screenshot. GPU rendering is used and read_viewport is not supported.\n"); + } const char *msg = NULL; if (ret) @@ -329,10 +337,14 @@ void rarch_render_cached_frame(void) g_extern.recording = false; #endif + const void *frame = g_extern.frame_cache.data; + if (frame == RETRO_HW_FRAME_BUFFER_VALID) + frame = NULL; // Dupe + // Not 100% safe, since the library might have // freed the memory, but no known implementations do this :D // It would be really stupid at any rate ... - video_frame(g_extern.frame_cache.data, + video_frame(frame, g_extern.frame_cache.width, g_extern.frame_cache.height, g_extern.frame_cache.pitch); @@ -1291,6 +1303,12 @@ static void init_recording(void) if (!g_extern.recording) return; + if (!g_settings.video.gpu_record && g_extern.system.hw_render_callback.context_type) + { + RARCH_WARN("Libretro core is hardware rendered. Must use post-shaded FFmpeg recording as well.\n"); + return; + } + double fps = g_extern.system.av_info.timing.fps; double samplerate = g_extern.system.av_info.timing.sample_rate; RARCH_LOG("Custom timing given: FPS: %.4f, Sample rate: %.4f\n", (float)fps, (float)samplerate); From 6758bca69d0f0ed2836bce59da359792aeaf1224 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 28 Mar 2013 12:46:40 +0100 Subject: [PATCH 07/14] Test GL core works in GLES as well. --- libretro-test-gl/Makefile | 13 ++++++++++--- libretro-test-gl/libretro-test.c | 26 ++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/libretro-test-gl/Makefile b/libretro-test-gl/Makefile index dd4bf79d17..30a0eaed59 100644 --- a/libretro-test-gl/Makefile +++ b/libretro-test-gl/Makefile @@ -16,17 +16,17 @@ ifeq ($(platform), unix) TARGET := libretro.so fpic := -fPIC SHARED := -shared -Wl,--version-script=link.T -Wl,--no-undefined - LIBS := -lGL + GL_LIB := -lGL else ifeq ($(platform), osx) TARGET := libretro.dylib fpic := -fPIC SHARED := -dynamiclib - LIBS := -framework OpenGL + GL_LIB := -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 + GL_LIB := -lopengl32 endif ifeq ($(DEBUG), 1) @@ -38,6 +38,13 @@ endif OBJECTS := libretro-test.o CFLAGS += -std=gnu99 -Wall -pedantic $(fpic) +ifeq ($(GLES), 1) + CFLAGS += -DGLES + LIBS += -lGLESv2 +else + LIBS += $(GL_LIB) +endif + all: $(TARGET) $(TARGET): $(OBJECTS) diff --git a/libretro-test-gl/libretro-test.c b/libretro-test-gl/libretro-test.c index 5f43e6c9d2..e8ff2ff14e 100644 --- a/libretro-test-gl/libretro-test.c +++ b/libretro-test-gl/libretro-test.c @@ -4,6 +4,27 @@ #include #include #include + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +static struct retro_hw_render_callback hw_render; + +#ifdef GLES +#include +#define pglCreateProgram glCreateProgram +#define pglCreateShader glCreateShader +#define pglCompileShader glCompileShader +#define pglUseProgram glUseProgram +#define pglShaderSource glShaderSource +#define pglAttachShader glAttachShader +#define pglLinkProgram glLinkProgram +#define pglBindFramebuffer glBindFramebuffer +#define pglGetUniformLocation glGetUniformLocation +#define pglUniformMatrix4fv glUniformMatrix4fv +#define pglGetAttribLocation glGetAttribLocation +#define pglVertexAttribPointer glVertexAttribPointer +#define pglEnableVertexAttribArray glEnableVertexAttribArray +#define pglDisableVertexAttribArray glEnableVertexAttribArray +#else #include #define GL_GLEXT_PROTOTYPES #include @@ -23,7 +44,6 @@ static PFNGLVERTEXATTRIBPOINTERPROC pglVertexAttribPointer; static PFNGLENABLEVERTEXATTRIBARRAYPROC pglEnableVertexAttribArray; static PFNGLDISABLEVERTEXATTRIBARRAYPROC pglDisableVertexAttribArray; -static struct retro_hw_render_callback hw_render; struct gl_proc_map { @@ -32,7 +52,6 @@ struct gl_proc_map }; #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), @@ -60,6 +79,7 @@ static void init_gl_proc(void) memcpy(proc_map[i].proc, &proc, sizeof(proc)); } } +#endif static GLuint prog; @@ -237,7 +257,9 @@ void retro_run(void) static void context_reset(void) { fprintf(stderr, "Context reset!\n"); +#ifndef GLES init_gl_proc(); +#endif compile_program(); } From f4e9547e686ce03a76812d8ec04349cf182886f0 Mon Sep 17 00:00:00 2001 From: Themaister Date: Fri, 29 Mar 2013 02:12:08 +0100 Subject: [PATCH 08/14] Fix Win32 HW render. --- gfx/gl.c | 18 +++++++++++++++--- libretro-test-gl/Makefile | 3 ++- libretro-test-gl/libretro-test.c | 1 + 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/gfx/gl.c b/gfx/gl.c index eba64aba59..3807c9ef6e 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -700,10 +700,13 @@ 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) +bool gl_init_hw_render(gl_t *gl, unsigned width, unsigned height) { RARCH_LOG("[GL]: Initializing HW render (%u x %u).\n", width, height); + if (!load_fbo_proc(gl)) + return false; + glBindTexture(GL_TEXTURE_2D, 0); pglGenFramebuffers(TEXTURES, gl->hw_render_fbo); @@ -713,11 +716,15 @@ void gl_init_hw_render(gl_t *gl, unsigned width, unsigned height) 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"); + return false; + } } pglBindFramebuffer(GL_FRAMEBUFFER, 0); gl->hw_render_fbo_init = true; + return true; } #endif @@ -1936,8 +1943,13 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo // 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); + if (g_extern.system.hw_render_callback.context_type == RETRO_HW_CONTEXT_OPENGL + && !gl_init_hw_render(gl, gl->tex_w, gl->tex_h)) + { + context_destroy_func(); + free(gl); + return NULL; + } #endif if (input && input_data) diff --git a/libretro-test-gl/Makefile b/libretro-test-gl/Makefile index 30a0eaed59..2ec4542b85 100644 --- a/libretro-test-gl/Makefile +++ b/libretro-test-gl/Makefile @@ -27,6 +27,7 @@ else TARGET := retro.dll SHARED := -shared -static-libgcc -static-libstdc++ -s -Wl,--version-script=link.T -Wl,--no-undefined GL_LIB := -lopengl32 + CFLAGS += -I.. endif ifeq ($(DEBUG), 1) @@ -48,7 +49,7 @@ endif all: $(TARGET) $(TARGET): $(OBJECTS) - $(CC) $(fpic) $(SHARED) $(LIBS) $(INCLUDES) -o $@ $(OBJECTS) -lm + $(CC) $(fpic) $(SHARED) $(INCLUDES) -o $@ $(OBJECTS) $(LIBS) -lm %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< diff --git a/libretro-test-gl/libretro-test.c b/libretro-test-gl/libretro-test.c index e8ff2ff14e..54f6ddd838 100644 --- a/libretro-test-gl/libretro-test.c +++ b/libretro-test-gl/libretro-test.c @@ -277,6 +277,7 @@ bool retro_load_game(const struct retro_game_info *info) if (!environ_cb(RETRO_ENVIRONMENT_SET_HW_RENDER, &hw_render)) return false; + fprintf(stderr, "Loaded game!\n"); (void)info; return true; } From 50af927de61b3fd22ab5e256f83c71be7063db06 Mon Sep 17 00:00:00 2001 From: Themaister Date: Fri, 29 Mar 2013 02:50:42 +0100 Subject: [PATCH 09/14] Add depth/stencil buffers to HW GL. --- gfx/gl.c | 69 +++++++++++++++++++++++++++++++- gfx/gl_common.h | 4 ++ libretro-test-gl/libretro-test.c | 36 ++++++++++++----- libretro.h | 2 + 4 files changed, 100 insertions(+), 11 deletions(-) diff --git a/gfx/gl.c b/gfx/gl.c index 3807c9ef6e..897f21e37b 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -135,6 +135,11 @@ static PFNGLBINDFRAMEBUFFERPROC pglBindFramebuffer; static PFNGLFRAMEBUFFERTEXTURE2DPROC pglFramebufferTexture2D; static PFNGLCHECKFRAMEBUFFERSTATUSPROC pglCheckFramebufferStatus; static PFNGLDELETEFRAMEBUFFERSPROC pglDeleteFramebuffers; +static PFNGLGENRENDERBUFFERSPROC pglGenRenderbuffers; +static PFNGLBINDRENDERBUFFERPROC pglBindRenderbuffer; +static PFNGLFRAMEBUFFERRENDERBUFFERPROC pglFramebufferRenderbuffer; +static PFNGLRENDERBUFFERSTORAGEPROC pglRenderbufferStorage; +static PFNGLDELETERENDERBUFFERSPROC pglDeleteRenderbuffers; static bool load_fbo_proc(gl_t *gl) { @@ -143,9 +148,17 @@ static bool load_fbo_proc(gl_t *gl) LOAD_GL_SYM(FramebufferTexture2D); LOAD_GL_SYM(CheckFramebufferStatus); LOAD_GL_SYM(DeleteFramebuffers); + LOAD_GL_SYM(GenRenderbuffers); + LOAD_GL_SYM(BindRenderbuffer); + LOAD_GL_SYM(FramebufferRenderbuffer); + LOAD_GL_SYM(RenderbufferStorage); + LOAD_GL_SYM(DeleteRenderbuffers); return pglGenFramebuffers && pglBindFramebuffer && pglFramebufferTexture2D && - pglCheckFramebufferStatus && pglDeleteFramebuffers; + pglCheckFramebufferStatus && pglDeleteFramebuffers && + pglGenRenderbuffers && pglBindRenderbuffer && + pglFramebufferRenderbuffer && pglRenderbufferStorage && + pglDeleteRenderbuffers; } #elif defined(HAVE_OPENGLES2) #define pglGenFramebuffers glGenFramebuffers @@ -153,6 +166,11 @@ static bool load_fbo_proc(gl_t *gl) #define pglFramebufferTexture2D glFramebufferTexture2D #define pglCheckFramebufferStatus glCheckFramebufferStatus #define pglDeleteFramebuffers glDeleteFramebuffers +#define pglGenRenderbuffers glGenRenderbuffers +#define pglBindRenderbuffer glBindRenderbuffer +#define pglFramebufferRenderbuffer glFramebufferRenderbuffer +#define pglRenderbufferStorage glRenderbufferStorage +#define pglDeleteRenderbuffers glDeleteRenderbuffers #define load_fbo_proc(gl) (true) #elif defined(HAVE_OPENGLES) #define pglGenFramebuffers glGenFramebuffersOES @@ -160,6 +178,11 @@ static bool load_fbo_proc(gl_t *gl) #define pglFramebufferTexture2D glFramebufferTexture2DOES #define pglCheckFramebufferStatus glCheckFramebufferStatusOES #define pglDeleteFramebuffers glDeleteFramebuffersOES +#define pglGenRenderbuffers glGenRenderbuffersOES +#define pglBindRenderbuffer glBindRenderbufferOES +#define pglFramebufferRenderbuffer glFramebufferRenderbufferOES +#define pglRenderbufferStorage glRenderbufferStorageOES +#define pglDeleteRenderbuffers glDeleteRenderbuffersOES #define GL_FRAMEBUFFER GL_FRAMEBUFFER_OES #define GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_EXT #define GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_OES @@ -170,6 +193,11 @@ static bool load_fbo_proc(gl_t *gl) #define pglFramebufferTexture2D glFramebufferTexture2D #define pglCheckFramebufferStatus glCheckFramebufferStatus #define pglDeleteFramebuffers glDeleteFramebuffers +#define pglGenRenderbuffers glGenRenderbuffers +#define pglBindRenderbuffer glBindRenderbuffer +#define pglFramebufferRenderbuffer glFramebufferRenderbuffer +#define pglRenderbufferStorage glRenderbufferStorage +#define pglDeleteRenderbuffers glDeleteRenderbuffers #define load_fbo_proc(gl) (true) #endif #endif @@ -710,10 +738,44 @@ bool gl_init_hw_render(gl_t *gl, unsigned width, unsigned height) glBindTexture(GL_TEXTURE_2D, 0); pglGenFramebuffers(TEXTURES, gl->hw_render_fbo); + bool depth = g_extern.system.hw_render_callback.depth; + bool stencil = g_extern.system.hw_render_callback.stencil; + + if (depth) + { + pglGenRenderbuffers(TEXTURES, gl->hw_render_depth); + gl->hw_render_depth_init = true; + } + + if (stencil) + { + pglGenRenderbuffers(TEXTURES, gl->hw_render_stencil); + gl->hw_render_stencil_init = true; + } + 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); + + if (depth) + { + pglBindRenderbuffer(GL_RENDERBUFFER, gl->hw_render_depth[i]); + pglRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, + width, height); + pglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, gl->hw_render_depth[i]); + } + + if (stencil) + { + pglBindRenderbuffer(GL_RENDERBUFFER, gl->hw_render_stencil[i]); + pglRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, + width, height); + pglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, gl->hw_render_stencil[i]); + } + GLenum status = pglCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { @@ -723,6 +785,7 @@ bool gl_init_hw_render(gl_t *gl, unsigned width, unsigned height) } pglBindFramebuffer(GL_FRAMEBUFFER, 0); + pglBindRenderbuffer(GL_RENDERBUFFER, 0); gl->hw_render_fbo_init = true; return true; } @@ -1593,6 +1656,10 @@ static void gl_free(void *data) if (gl->hw_render_fbo_init) pglDeleteFramebuffers(TEXTURES, gl->hw_render_fbo); + if (gl->hw_render_depth) + pglDeleteRenderbuffers(TEXTURES, gl->hw_render_depth); + if (gl->hw_render_stencil) + pglDeleteRenderbuffers(TEXTURES, gl->hw_render_stencil); gl->hw_render_fbo_init = false; #endif diff --git a/gfx/gl_common.h b/gfx/gl_common.h index 814ba5611e..5160a17611 100644 --- a/gfx/gl_common.h +++ b/gfx/gl_common.h @@ -244,7 +244,11 @@ typedef struct gl bool fbo_inited; GLuint hw_render_fbo[TEXTURES]; + GLuint hw_render_depth[TEXTURES]; + GLuint hw_render_stencil[TEXTURES]; bool hw_render_fbo_init; + bool hw_render_depth_init; + bool hw_render_stencil_init; #endif bool should_resize; diff --git a/libretro-test-gl/libretro-test.c b/libretro-test-gl/libretro-test.c index 54f6ddd838..5c835f4ba3 100644 --- a/libretro-test-gl/libretro-test.c +++ b/libretro-test-gl/libretro-test.c @@ -218,10 +218,12 @@ void retro_run(void) pglBindFramebuffer(GL_FRAMEBUFFER, hw_render.get_current_framebuffer()); glClearColor(0.3, 0.4, 0.5, 1.0); glViewport(0, 0, 512, 512); - glClear(GL_COLOR_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); pglUseProgram(prog); + glEnable(GL_DEPTH_TEST); + int loc = pglGetUniformLocation(prog, "uMVP"); static unsigned frame_count; @@ -230,15 +232,6 @@ void retro_run(void) float cos_angle = cos(angle); float sin_angle = sin(angle); - const GLfloat mvp[] = { - cos_angle, -sin_angle, 0, 0, - sin_angle, cos_angle, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1, - }; - - pglUniformMatrix4fv(loc, 1, GL_FALSE, mvp); - int vloc = pglGetAttribLocation(prog, "aVertex"); pglVertexAttribPointer(vloc, 2, GL_FLOAT, GL_FALSE, 0, vertex); pglEnableVertexAttribArray(vloc); @@ -246,7 +239,28 @@ void retro_run(void) pglVertexAttribPointer(cloc, 4, GL_FLOAT, GL_FALSE, 0, color); pglEnableVertexAttribArray(cloc); + const GLfloat mvp[] = { + cos_angle, -sin_angle, 0, 0, + sin_angle, cos_angle, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, + }; + pglUniformMatrix4fv(loc, 1, GL_FALSE, mvp); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + cos_angle *= 0.5; + sin_angle *= 0.5; + const GLfloat mvp2[] = { + cos_angle, -sin_angle, 0, 0.0, + sin_angle, cos_angle, 0, 0.0, + 0, 0, 1, 0, + 0.4, 0.4, 0.2, 1, + }; + + pglUniformMatrix4fv(loc, 1, GL_FALSE, mvp2); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + pglUseProgram(0); pglDisableVertexAttribArray(vloc); pglDisableVertexAttribArray(cloc); @@ -274,6 +288,8 @@ bool retro_load_game(const struct retro_game_info *info) hw_render.context_type = RETRO_HW_CONTEXT_OPENGL; hw_render.context_reset = context_reset; + hw_render.depth = true; + hw_render.stencil = true; if (!environ_cb(RETRO_ENVIRONMENT_SET_HW_RENDER, &hw_render)) return false; diff --git a/libretro.h b/libretro.h index 048bed8fbe..e710337ce6 100755 --- a/libretro.h +++ b/libretro.h @@ -462,6 +462,8 @@ struct retro_hw_render_callback 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. + bool depth; // Set if render buffers should have depth component attached. + bool stencil; // Set if render buffers should have stencil component attached. }; // Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK. Called by the frontend in response to keyboard events. From 403a3faea2f04216ef48101bd961aee32deb928b Mon Sep 17 00:00:00 2001 From: Themaister Date: Fri, 29 Mar 2013 14:11:53 +0100 Subject: [PATCH 10/14] Clean out some more GL state. --- gfx/gl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gfx/gl.c b/gfx/gl.c index 4376be76de..c27b385694 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -1494,6 +1494,8 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei glEnable(GL_TEXTURE_2D); #endif glDisable(GL_DEPTH_TEST); + glDisable(GL_ALPHA_TEST); + glDisable(GL_STENCIL_TEST); glDisable(GL_CULL_FACE); glDisable(GL_DITHER); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); From 0604f8e7ee7591954b065fe467d5fbdcb66e59ef Mon Sep 17 00:00:00 2001 From: Themaister Date: Fri, 29 Mar 2013 14:12:51 +0100 Subject: [PATCH 11/14] Drop ALPHA_TEST. It is legacy GL. --- gfx/gl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/gfx/gl.c b/gfx/gl.c index c27b385694..276c60ae94 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -1494,7 +1494,6 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei glEnable(GL_TEXTURE_2D); #endif glDisable(GL_DEPTH_TEST); - glDisable(GL_ALPHA_TEST); glDisable(GL_STENCIL_TEST); glDisable(GL_CULL_FACE); glDisable(GL_DITHER); From 063a2e091c39f066b3d9050b967f125173cdc445 Mon Sep 17 00:00:00 2001 From: Themaister Date: Fri, 29 Mar 2013 15:26:47 +0100 Subject: [PATCH 12/14] Be more explicit about GLES2 or GL context. --- dynamic.c | 30 ++++++++++++++++++++++++++++++ gfx/gl.c | 8 +++++++- libretro-test-gl/libretro-test.c | 4 ++++ libretro.h | 3 ++- 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/dynamic.c b/dynamic.c index b09644577b..eee7d4a85a 100644 --- a/dynamic.c +++ b/dynamic.c @@ -560,6 +560,36 @@ 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; + switch (cb->context_type) + { + case RETRO_HW_CONTEXT_NONE: + RARCH_LOG("Requesting no HW context.\n"); + break; + +#if defined(HAVE_OPENGLES2) + case RETRO_HW_CONTEXT_OPENGLES2: + RARCH_LOG("Requesting OpenGLES2 context.\n"); + driver.video = &video_gl; + break; + + case RETRO_HW_CONTEXT_OPENGL: + RARCH_ERR("Requesting OpenGL context, but RetroArch is compiled against OpenGLES2. Cannot use HW context.\n"); + return false; +#elif defined(HAVE_OPENGL) + case RETRO_HW_CONTEXT_OPENGLES2: + RARCH_ERR("Requesting OpenGLES2 context, but RetroArch is compiled against OpenGL. Cannot use HW context.\n"); + return false; + + case RETRO_HW_CONTEXT_OPENGL: + RARCH_LOG("Requesting OpenGL context.\n"); + driver.video = &video_gl; + break; +#endif + + default: + RARCH_LOG("Requesting unknown context.\n"); + return false; + } 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)); diff --git a/gfx/gl.c b/gfx/gl.c index 276c60ae94..31248b203a 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -2013,7 +2013,13 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo // 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 +#ifdef HAVE_OPENGLES2 + enum retro_hw_context_type desired = RETRO_HW_CONTEXT_OPENGLES2; +#else + enum retro_hw_context_type desired = RETRO_HW_CONTEXT_OPENGL; +#endif + + if (g_extern.system.hw_render_callback.context_type == desired && !gl_init_hw_render(gl, gl->tex_w, gl->tex_h)) { context_destroy_func(); diff --git a/libretro-test-gl/libretro-test.c b/libretro-test-gl/libretro-test.c index 5c835f4ba3..d9ca3605b4 100644 --- a/libretro-test-gl/libretro-test.c +++ b/libretro-test-gl/libretro-test.c @@ -286,7 +286,11 @@ bool retro_load_game(const struct retro_game_info *info) return false; } +#ifdef GLES + hw_render.context_type = RETRO_HW_CONTEXT_OPENGLES2; +#else hw_render.context_type = RETRO_HW_CONTEXT_OPENGL; +#endif hw_render.context_reset = context_reset; hw_render.depth = true; hw_render.stencil = true; diff --git a/libretro.h b/libretro.h index e710337ce6..7f4a53740a 100755 --- a/libretro.h +++ b/libretro.h @@ -451,7 +451,8 @@ typedef retro_proc_address_t (*retro_hw_get_proc_address_t)(const char *sym); enum retro_hw_context_type { RETRO_HW_CONTEXT_NONE = 0, - RETRO_HW_CONTEXT_OPENGL, + RETRO_HW_CONTEXT_OPENGL, // OpenGL 2.x. Latest version available before 3.x+. + RETRO_HW_CONTEXT_OPENGLES2, // GLES 2.0 RETRO_HW_CONTEXT_DUMMY = INT_MAX }; From 5bc2ea318706e63c735b5e498d8d119800aa6d88 Mon Sep 17 00:00:00 2001 From: Themaister Date: Fri, 29 Mar 2013 16:13:00 +0100 Subject: [PATCH 13/14] Use VAOs for completion. --- libretro-test-gl/libretro-test.c | 79 ++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/libretro-test-gl/libretro-test.c b/libretro-test-gl/libretro-test.c index d9ca3605b4..36771c5a7e 100644 --- a/libretro-test-gl/libretro-test.c +++ b/libretro-test-gl/libretro-test.c @@ -8,26 +8,13 @@ #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) static struct retro_hw_render_callback hw_render; -#ifdef GLES +#define GL_GLEXT_PROTOTYPES +#if defined(GLES) && 0 #include -#define pglCreateProgram glCreateProgram -#define pglCreateShader glCreateShader -#define pglCompileShader glCompileShader -#define pglUseProgram glUseProgram -#define pglShaderSource glShaderSource -#define pglAttachShader glAttachShader -#define pglLinkProgram glLinkProgram -#define pglBindFramebuffer glBindFramebuffer -#define pglGetUniformLocation glGetUniformLocation -#define pglUniformMatrix4fv glUniformMatrix4fv -#define pglGetAttribLocation glGetAttribLocation -#define pglVertexAttribPointer glVertexAttribPointer -#define pglEnableVertexAttribArray glEnableVertexAttribArray -#define pglDisableVertexAttribArray glEnableVertexAttribArray #else #include -#define GL_GLEXT_PROTOTYPES #include +#endif static PFNGLCREATEPROGRAMPROC pglCreateProgram; static PFNGLCREATESHADERPROC pglCreateShader; @@ -43,7 +30,12 @@ static PFNGLGETATTRIBLOCATIONPROC pglGetAttribLocation; static PFNGLVERTEXATTRIBPOINTERPROC pglVertexAttribPointer; static PFNGLENABLEVERTEXATTRIBARRAYPROC pglEnableVertexAttribArray; static PFNGLDISABLEVERTEXATTRIBARRAYPROC pglDisableVertexAttribArray; - +static PFNGLGENVERTEXARRAYSPROC pglGenVertexArrays; +static PFNGLBINDVERTEXARRAYPROC pglBindVertexArray; +static PFNGLDELETEVERTEXARRAYSPROC pglDeleteVertexArray; +static PFNGLGENBUFFERSPROC pglGenBuffers; +static PFNGLBUFFERDATAPROC pglBufferData; +static PFNGLBINDBUFFERPROC pglBindBuffer; struct gl_proc_map { @@ -67,6 +59,12 @@ static const struct gl_proc_map proc_map[] = { PROC_BIND(VertexAttribPointer), PROC_BIND(EnableVertexAttribArray), PROC_BIND(DisableVertexAttribArray), + PROC_BIND(GenVertexArrays), + PROC_BIND(BindVertexArray), + PROC_BIND(DeleteVertexArray), + PROC_BIND(GenBuffers), + PROC_BIND(BufferData), + PROC_BIND(BindBuffer), }; static void init_gl_proc(void) @@ -79,25 +77,22 @@ static void init_gl_proc(void) memcpy(proc_map[i].proc, &proc, sizeof(proc)); } } -#endif static GLuint prog; +static GLuint vao; +static GLuint vbo; -static const GLfloat vertex[] = { +static const GLfloat vertex_data[] = { -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, -}; - -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;", @@ -132,6 +127,29 @@ static void compile_program(void) pglLinkProgram(prog); } +static void setup_vao(void) +{ + pglUseProgram(prog); + + pglGenVertexArrays(1, &vao); + pglBindVertexArray(vao); + + pglGenBuffers(1, &vbo); + pglBindBuffer(GL_ARRAY_BUFFER, vbo); + pglBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); + + int vloc = pglGetAttribLocation(prog, "aVertex"); + pglVertexAttribPointer(vloc, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); + pglEnableVertexAttribArray(vloc); + int cloc = pglGetAttribLocation(prog, "aColor"); + pglVertexAttribPointer(cloc, 4, GL_FLOAT, GL_FALSE, 0, (void*)(8 * sizeof(GLfloat))); + pglEnableVertexAttribArray(cloc); + + pglBindBuffer(GL_ARRAY_BUFFER, 0); + pglBindVertexArray(0); + pglUseProgram(0); +} + void retro_init(void) {} @@ -221,6 +239,7 @@ void retro_run(void) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); pglUseProgram(prog); + pglBindVertexArray(vao); glEnable(GL_DEPTH_TEST); @@ -232,13 +251,6 @@ void retro_run(void) float cos_angle = cos(angle); float sin_angle = sin(angle); - 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); - const GLfloat mvp[] = { cos_angle, -sin_angle, 0, 0, sin_angle, cos_angle, 0, 0, @@ -260,10 +272,8 @@ void retro_run(void) pglUniformMatrix4fv(loc, 1, GL_FALSE, mvp2); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - pglUseProgram(0); - pglDisableVertexAttribArray(vloc); - pglDisableVertexAttribArray(cloc); + pglBindVertexArray(0); video_cb(RETRO_HW_FRAME_BUFFER_VALID, 512, 512, 0); } @@ -271,10 +281,9 @@ void retro_run(void) static void context_reset(void) { fprintf(stderr, "Context reset!\n"); -#ifndef GLES init_gl_proc(); -#endif compile_program(); + setup_vao(); } bool retro_load_game(const struct retro_game_info *info) From da1eee609e7e2e5db5864a375f56da458fcacb8a Mon Sep 17 00:00:00 2001 From: Themaister Date: Sat, 30 Mar 2013 13:59:21 +0100 Subject: [PATCH 14/14] Mark SET_HW_RENDER as experimental more explicitly. --- libretro.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libretro.h b/libretro.h index 7f4a53740a..b614eb7f3a 100755 --- a/libretro.h +++ b/libretro.h @@ -333,6 +333,8 @@ enum retro_mod RETROKMOD_DUMMY = INT_MAX // Ensure sizeof(enum) == sizeof(int) }; +// If set, this call is not part of the public libretro API yet. It can change or be removed at any time. +#define RETRO_ENVIRONMENT_EXPERIMENTAL 0x10000 // Environment commands. #define RETRO_ENVIRONMENT_SET_ROTATION 1 // const unsigned * -- @@ -421,7 +423,7 @@ 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 +#define RETRO_ENVIRONMENT_SET_HW_RENDER (14 | RETRO_ENVIRONMENT_EXPERIMENTAL) // 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.