diff --git a/gfx/context/androidegl_ctx.c b/gfx/context/androidegl_ctx.c index a687eba0c4..dfb3433a91 100644 --- a/gfx/context/androidegl_ctx.c +++ b/gfx/context/androidegl_ctx.c @@ -312,7 +312,7 @@ static bool gfx_ctx_init_egl_image_buffer(const video_info_t *video) return false; } -static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, void **image_handle) +static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, unsigned index, void **image_handle) { return false; } diff --git a/gfx/context/drm_egl_ctx.c b/gfx/context/drm_egl_ctx.c index 6f0a7646d8..b7f76aaeb5 100644 --- a/gfx/context/drm_egl_ctx.c +++ b/gfx/context/drm_egl_ctx.c @@ -630,7 +630,7 @@ static bool gfx_ctx_init_egl_image_buffer(const video_info_t *video) return false; } -static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, void **image_handle) +static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, unsigned index, void **image_handle) { return false; } diff --git a/gfx/context/glx_ctx.c b/gfx/context/glx_ctx.c index 4dacbe1bb5..c1aee3f2e9 100644 --- a/gfx/context/glx_ctx.c +++ b/gfx/context/glx_ctx.c @@ -467,7 +467,7 @@ static bool gfx_ctx_init_egl_image_buffer(const video_info_t *video) return false; } -static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, void **image_handle) +static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, unsigned index, void **image_handle) { return false; } diff --git a/gfx/context/ps3_ctx.c b/gfx/context/ps3_ctx.c index 9fae55c697..017bb1f885 100644 --- a/gfx/context/ps3_ctx.c +++ b/gfx/context/ps3_ctx.c @@ -383,7 +383,7 @@ static bool gfx_ctx_init_egl_image_buffer(const video_info_t *video) return false; } -static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, void **image_handle) +static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, unsigned index, void **image_handle) { return false; } diff --git a/gfx/context/sdl_ctx.c b/gfx/context/sdl_ctx.c index 7db4f694d4..f195e1a328 100644 --- a/gfx/context/sdl_ctx.c +++ b/gfx/context/sdl_ctx.c @@ -321,7 +321,7 @@ static bool gfx_ctx_init_egl_image_buffer(const video_info_t *video) return false; } -static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, void **image_handle) +static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, unsigned index, void **image_handle) { return false; } diff --git a/gfx/context/vc_egl_ctx.c b/gfx/context/vc_egl_ctx.c index 4d866c991e..f2c5bdf4c5 100644 --- a/gfx/context/vc_egl_ctx.c +++ b/gfx/context/vc_egl_ctx.c @@ -50,10 +50,12 @@ static enum gfx_ctx_api g_api; static unsigned g_fb_width; static unsigned g_fb_height; -static EGLImageKHR eglBuffer; +static EGLImageKHR eglBuffer[MAX_EGLIMAGE_TEXTURES]; static EGLContext g_eglimage_ctx; static EGLSurface g_pbuff_surf; -static VGImage g_egl_vgimage; +static VGImage g_egl_vgimage[MAX_EGLIMAGE_TEXTURES]; +static bool g_smooth; +static unsigned g_egl_res; PFNEGLCREATEIMAGEKHRPROC peglCreateImageKHR; PFNEGLDESTROYIMAGEKHRPROC peglDestroyImageKHR; @@ -235,23 +237,42 @@ static bool gfx_ctx_set_video_mode( return true; } +static bool gfx_ctx_bind_api(enum gfx_ctx_api api) +{ + g_api = api; + switch (api) + { + case GFX_CTX_OPENGL_API: + return eglBindAPI(EGL_OPENGL_API); + case GFX_CTX_OPENGL_ES_API: + return eglBindAPI(EGL_OPENGL_ES_API); + case GFX_CTX_OPENVG_API: + return eglBindAPI(EGL_OPENVG_API); + default: + return false; + } +} + static void gfx_ctx_destroy(void) { if (g_egl_dpy) { - if (eglBuffer && peglDestroyImageKHR) + for (unsigned i = 0; i < MAX_EGLIMAGE_TEXTURES; i++) { - eglBindAPI(EGL_OPENGL_VG_API); - eglMakeCurrent(g_egl_dpy, g_pbuff_surf, g_pbuff_surf, g_eglimage_ctx); - peglDestroyImageKHR(e_egl_dpy, eglBuffer); - } + if (eglBuffer[i] && peglDestroyImageKHR) + { + eglBindAPI(EGL_OPENVG_API); + eglMakeCurrent(g_egl_dpy, g_pbuff_surf, g_pbuff_surf, g_eglimage_ctx); + peglDestroyImageKHR(g_egl_dpy, eglBuffer[i]); + } - if (g_egl_vgimage) - { - eglBindAPI(EGL_OPENGL_VG_API); - eglMakeCurrent(g_egl_dpy, g_pbuff_surf, g_pbuff_surf, g_eglimage_ctx); - vgDestroyImage(g_egl_vgimage); + if (g_egl_vgimage[i]) + { + eglBindAPI(EGL_OPENVG_API); + eglMakeCurrent(g_egl_dpy, g_pbuff_surf, g_pbuff_surf, g_eglimage_ctx); + vgDestroyImage(g_egl_vgimage[i]); + } } if (g_egl_ctx) @@ -263,7 +284,7 @@ static void gfx_ctx_destroy(void) if (g_eglimage_ctx) { - eglBindAPI(EGL_OPENGL_VG_API); + eglBindAPI(EGL_OPENVG_API); eglMakeCurrent(g_egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(g_egl_dpy, g_eglimage_ctx); } @@ -276,11 +297,11 @@ static void gfx_ctx_destroy(void) if (g_pbuff_surf) { - eglBindAPI(EGL_OPENGL_VG_API); + eglBindAPI(EGL_OPENVG_API); eglDestroySurface(g_egl_dpy, g_pbuff_surf); } - eglBindAPI(EGL_OPENGL_VG_API); + eglBindAPI(EGL_OPENVG_API); eglMakeCurrent(g_egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); gfx_ctx_bind_api(g_api); eglMakeCurrent(g_egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); @@ -288,14 +309,18 @@ static void gfx_ctx_destroy(void) } g_egl_ctx = NULL; - g_eglimage_ctx = NULL + g_eglimage_ctx = NULL; g_egl_surf = NULL; g_pbuff_surf = NULL; g_egl_dpy = NULL; - eglBuffer = NULL; - g_egl_vgimage = NULL; g_config = 0; g_inited = false; + + for (unsigned i = 0; i < MAX_EGLIMAGE_TEXTURES; i++) + { + eglBuffer[i] = NULL; + g_egl_vgimage[i] = 0; + } } static void gfx_ctx_input_driver(const input_driver_t **input, void **input_data) @@ -315,22 +340,6 @@ static gfx_ctx_proc_t gfx_ctx_get_proc_address(const char *symbol) return eglGetProcAddress(symbol); } -static bool gfx_ctx_bind_api(enum gfx_ctx_api api) -{ - g_api = api; - switch (api) - { - case GFX_CTX_OPENGL_API: - return eglBindAPI(EGL_OPENGL_API); - case GFX_CTX_OPENGL_ES_API: - return eglBindAPI(EGL_OPENGL_ES_API); - case GFX_CTX_OPENVG_API: - return eglBindAPI(EGL_OPENVG_API); - default: - return false; - } -} - static float gfx_ctx_translate_aspect(unsigned width, unsigned height) { // check for SD televisions: they should always be 4:3. @@ -355,12 +364,12 @@ static bool gfx_ctx_init_egl_image_buffer(const video_info_t *video) return false; } - unsigned res = video->input_scale * RARCH_SCALE_BASE; + g_egl_res = video->input_scale * RARCH_SCALE_BASE; EGLint pbufsurface_list[] = { - EGL_WIDTH, res, - EGL_HEIGHT, res, + EGL_WIDTH, g_egl_res, + EGL_HEIGHT, g_egl_res, EGL_NONE }; @@ -381,6 +390,7 @@ static bool gfx_ctx_init_egl_image_buffer(const video_info_t *video) goto fail; } + // test to make sure we can switch context result = eglMakeCurrent(g_egl_dpy, g_pbuff_surf, g_pbuff_surf, g_eglimage_ctx); if (result == EGL_FALSE) { @@ -388,14 +398,12 @@ static bool gfx_ctx_init_egl_image_buffer(const video_info_t *video) goto fail; } - g_egl_vgimage = vgCreateImage(VG_sXRGB_8888, res, res, video->smooth ? VG_IMAGE_QUALITY_BETTER : VG_IMAGE_QUALITY_NONANTIALIASED); - eglBuffer = peglCreateImageKHR(g_egl_dpy, g_eglimage_ctx, EGL_VG_PARENT_IMAGE_KHR, (EGLClientBuffer)g_egl_vgimage, NULL); - gfx_ctx_bind_api(g_api); eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx); + g_smooth = video->smooth; return true; - + fail: if (g_pbuff_surf != EGL_NO_SURFACE) { @@ -415,27 +423,33 @@ fail: return false; } -static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, void **image_handle) +static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, unsigned index, void **image_handle) { - static bool first = true; + bool ret = false; + + if (index >= MAX_EGLIMAGE_TEXTURES) + { + *image_handle = NULL; + return false; + } + eglBindAPI(EGL_OPENVG_API); eglMakeCurrent(g_egl_dpy, g_pbuff_surf, g_pbuff_surf, g_eglimage_ctx); - vgImageSubData(g_egl_vgimage, frame, pitch, (rgb32 ? VG_sXRGB_8888 : VG_sARGB_1555), 0, 0, width, height); - *image_handle = eglBuffer; + if (!eglBuffer[index] || !g_egl_vgimage[index]) + { + g_egl_vgimage[index] = vgCreateImage(VG_sXRGB_8888, g_egl_res, g_egl_res, g_smooth ? VG_IMAGE_QUALITY_BETTER : VG_IMAGE_QUALITY_NONANTIALIASED); + eglBuffer[index] = peglCreateImageKHR(g_egl_dpy, g_eglimage_ctx, EGL_VG_PARENT_IMAGE_KHR, (EGLClientBuffer)g_egl_vgimage[index], NULL); + ret = true; + } + + vgImageSubData(g_egl_vgimage[index], frame, pitch, (rgb32 ? VG_sXRGB_8888 : VG_sARGB_1555), 0, 0, width, height); + *image_handle = eglBuffer[index]; gfx_ctx_bind_api(g_api); eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx); - if (first) - { - first = false; - return true; - } - else - { - return false; - } + return ret; } const gfx_ctx_driver_t gfx_ctx_videocore = { diff --git a/gfx/context/wgl_ctx.c b/gfx/context/wgl_ctx.c index e15fecf502..4358907668 100644 --- a/gfx/context/wgl_ctx.c +++ b/gfx/context/wgl_ctx.c @@ -409,7 +409,7 @@ static bool gfx_ctx_init_egl_image_buffer(const video_info_t *video) return false; } -static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, void **image_handle) +static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, unsigned index, void **image_handle) { return false; } diff --git a/gfx/context/xdk_ctx.c b/gfx/context/xdk_ctx.c index ec16af9adc..40c6f654f8 100644 --- a/gfx/context/xdk_ctx.c +++ b/gfx/context/xdk_ctx.c @@ -530,7 +530,7 @@ static bool gfx_ctx_init_egl_image_buffer(const video_info_t *video) return false; } -static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, void **image_handle) +static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, unsigned index, void **image_handle) { return false; } diff --git a/gfx/context/xegl_ctx.c b/gfx/context/xegl_ctx.c index f454f7efb8..bd6a94e8f9 100644 --- a/gfx/context/xegl_ctx.c +++ b/gfx/context/xegl_ctx.c @@ -508,7 +508,7 @@ static bool gfx_ctx_init_egl_image_buffer(const video_info_t *video) return false; } -static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, void **image_handle) +static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, unsigned index, void **image_handle) { return false; } diff --git a/gfx/gfx_context.h b/gfx/gfx_context.h index fb756a9e98..a6611bd3c0 100644 --- a/gfx/gfx_context.h +++ b/gfx/gfx_context.h @@ -23,6 +23,8 @@ #include "../config.h" #endif +#define MAX_EGLIMAGE_TEXTURES 32 + enum gfx_ctx_api { GFX_CTX_OPENGL_API, @@ -80,12 +82,12 @@ typedef struct gfx_ctx_driver // Wraps whatever gl_proc_address() there is. gfx_ctx_proc_t (*get_proc_address)(const char*); - // Returns true if this context supports EGL Image buffers for screen drawing and was initalized correctly. + // Returns true if this context supports EGLImage buffers for screen drawing and was initalized correctly. bool (*init_egl_image_buffer)(const video_info_t*); - // Writes the frame to the EGL Image and sets image_handle to it. Returns true if a new image handle is created. - // Always returns true the first time it's called. The graphics core must handle a change in the handle correctly. - bool (*write_egl_image)(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, void **image_handle); + // Writes the frame to the EGLImage and sets image_handle to it. Returns true if a new image handle is created. + // Always returns true the first time it's called for a new index. The graphics core must handle a change in the handle correctly. + bool (*write_egl_image)(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, unsigned index, void **image_handle); // Human readable string. const char *ident; diff --git a/gfx/gl.c b/gfx/gl.c index 0e722620f9..8005d4e2fb 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -94,6 +94,17 @@ const GLfloat *default_vertex_ptr = vertexes_flipped; memcpy(&(pgl##SYM), &sym, sizeof(sym)); \ } +#ifdef HAVE_EGL +static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC pglEGLImageTargetTexture2DOES = NULL; + +static bool load_eglimage_proc(gl_t *gl) +{ + LOAD_GL_SYM(EGLImageTargetTexture2DOES); + + return pglEGLImageTargetTexture2DOES; +} +#endif + #ifdef HAVE_FBO #if defined(_WIN32) && !defined(RARCH_CONSOLE) static PFNGLGENFRAMEBUFFERSPROC pglGenFramebuffers = NULL; @@ -925,7 +936,21 @@ static void gl_init_textures(gl_t *gl) #else static inline void gl_copy_frame(gl_t *gl, const void *frame, unsigned width, unsigned height, unsigned pitch) { - if (gl->base_size == 2) // ARGB1555 => ARGB8888, SIMD-style :D +#ifdef HAVE_EGL + if (gl->egl_images) + { + EGLImageKHR img = 0; + bool new_egl = gl->ctx_driver->write_egl_image(frame, width, height, pitch, (gl->base_size == 4), gl->tex_index, &img); + rarch_assert(img != EGL_NO_IMAGE_KHR); + + if (new_egl) + { + pglEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)img); + } + } + else +#endif +if (gl->base_size == 2) // ARGB1555 => ARGB8888, SIMD-style :D { glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(width * sizeof(uint32_t))); // Always use 32-bit textures. gl_convert_frame_rgb15_32(gl, gl->conv_buffer, frame, width, height, pitch); @@ -1024,6 +1049,9 @@ static void gl_render_menu(gl_t *gl) static bool gl_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg) { + RARCH_PERFORMANCE_INIT(frame_run); + RARCH_PERFORMANCE_START(frame_run); + gl_t *gl = (gl_t*)data; gl_shader_use(1); @@ -1095,6 +1123,9 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei gl->ctx_driver->update_window_title(false); #endif + RARCH_PERFORMANCE_STOP(frame_run); + RARCH_PERFORMANCE_LOG("gl_frame", frame_run); + #ifdef RARCH_CONSOLE if (!gl->block_swap) #endif @@ -1374,6 +1405,10 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo return NULL; } +#ifdef HAVE_EGL + gl->egl_images = load_eglimage_proc(gl) && gl->ctx_driver->init_egl_image_buffer(video); +#endif + return gl; } diff --git a/gfx/gl_common.h b/gfx/gl_common.h index d809a72689..fb6c6beb29 100644 --- a/gfx/gl_common.h +++ b/gfx/gl_common.h @@ -28,6 +28,11 @@ #include +#ifdef HAVE_EGL +#include +#include +#endif + #if defined(__APPLE__) #include #include @@ -36,8 +41,6 @@ #include #include #elif defined(HAVE_OPENGL_MODERN) -#include -#include #include #include #elif defined(HAVE_OPENGLES2) @@ -233,6 +236,10 @@ typedef struct gl bool menu_render; GLuint menu_texture_id; #endif + +#ifdef HAVE_EGL + bool egl_images; +#endif } gl_t; // Windows ... <_< diff --git a/gfx/vg.c b/gfx/vg.c index 98d3a945d1..13f8678445 100644 --- a/gfx/vg.c +++ b/gfx/vg.c @@ -350,17 +350,16 @@ static void vg_copy_frame(void *data, const void *frame, unsigned width, unsigne if (vg->mEglImageBuf) { EGLImageKHR img = 0; - bool new_egl = vg->driver->write_egl_image(frame, width, height, pitch, (vg->mTexType == VG_sXRGB_8888), &img); + bool new_egl = vg->driver->write_egl_image(frame, width, height, pitch, (vg->mTexType == VG_sXRGB_8888), 0, &img); rarch_assert(img != EGL_NO_IMAGE_KHR); if (new_egl) { vgDestroyImage(vg->mImage); - RARCH_LOG("[VG] %08x\n", (unsigned) img); vg->mImage = pvgCreateEGLImageTargetKHR((VGeglImageKHR) img); if (!vg->mImage) { - RARCH_ERR("[VG] Error creating image: %08x\n", vgGetError()); + RARCH_ERR("[VG:EGLImage] Error creating image: %08x\n", vgGetError()); exit(2); } vg->last_egl_image = img;