diff --git a/gfx/context/androidegl_ctx.c b/gfx/context/androidegl_ctx.c index ec631fa613..dfb3433a91 100644 --- a/gfx/context/androidegl_ctx.c +++ b/gfx/context/androidegl_ctx.c @@ -307,12 +307,12 @@ static bool gfx_ctx_has_focus(void) return true; } -static bool gfx_ctx_can_egl_image_buffer(void) +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; } @@ -332,7 +332,7 @@ const gfx_ctx_driver_t gfx_ctx_android = { gfx_ctx_swap_buffers, gfx_ctx_input_driver, NULL, - gfx_ctx_can_egl_image_buffer, + gfx_ctx_init_egl_image_buffer, gfx_ctx_write_egl_image, "android", }; diff --git a/gfx/context/drm_egl_ctx.c b/gfx/context/drm_egl_ctx.c index 614f7f00e5..b7f76aaeb5 100644 --- a/gfx/context/drm_egl_ctx.c +++ b/gfx/context/drm_egl_ctx.c @@ -625,12 +625,12 @@ static bool gfx_ctx_bind_api(enum gfx_ctx_api api) } } -static bool gfx_ctx_can_egl_image_buffer(void) +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; } @@ -650,7 +650,7 @@ const gfx_ctx_driver_t gfx_ctx_drm_egl = { gfx_ctx_swap_buffers, gfx_ctx_input_driver, gfx_ctx_get_proc_address, - gfx_ctx_can_egl_image_buffer, + gfx_ctx_init_egl_image_buffer, gfx_ctx_write_egl_image, "drm-egl", }; diff --git a/gfx/context/glx_ctx.c b/gfx/context/glx_ctx.c index e1f452447b..c1aee3f2e9 100644 --- a/gfx/context/glx_ctx.c +++ b/gfx/context/glx_ctx.c @@ -462,12 +462,12 @@ static bool gfx_ctx_bind_api(enum gfx_ctx_api api) return api == GFX_CTX_OPENGL_API; } -static bool gfx_ctx_can_egl_image_buffer(void) +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; } @@ -487,7 +487,7 @@ const gfx_ctx_driver_t gfx_ctx_glx = { gfx_ctx_swap_buffers, gfx_ctx_input_driver, gfx_ctx_get_proc_address, - gfx_ctx_can_egl_image_buffer, + gfx_ctx_init_egl_image_buffer, gfx_ctx_write_egl_image, "glx", }; diff --git a/gfx/context/ps3_ctx.c b/gfx/context/ps3_ctx.c index f6e7f97149..017bb1f885 100644 --- a/gfx/context/ps3_ctx.c +++ b/gfx/context/ps3_ctx.c @@ -378,12 +378,12 @@ static bool gfx_ctx_bind_api(enum gfx_ctx_api api) return api == GFX_CTX_OPENGL_API || GFX_CTX_OPENGL_ES_API; } -static bool gfx_ctx_can_egl_image_buffer(void) +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; } @@ -403,7 +403,7 @@ const gfx_ctx_driver_t gfx_ctx_ps3 = { gfx_ctx_swap_buffers, gfx_ctx_input_driver, NULL, - gfx_ctx_can_egl_image_buffer, + gfx_ctx_init_egl_image_buffer, gfx_ctx_write_egl_image, "ps3", diff --git a/gfx/context/sdl_ctx.c b/gfx/context/sdl_ctx.c index ca984b8ea6..f195e1a328 100644 --- a/gfx/context/sdl_ctx.c +++ b/gfx/context/sdl_ctx.c @@ -316,12 +316,12 @@ static bool gfx_ctx_bind_api(enum gfx_ctx_api api) return api == GFX_CTX_OPENGL_API; } -static bool gfx_ctx_can_egl_image_buffer(void) +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; } @@ -341,7 +341,7 @@ const gfx_ctx_driver_t gfx_ctx_sdl_gl = { gfx_ctx_swap_buffers, gfx_ctx_input_driver, gfx_ctx_get_proc_address, - gfx_ctx_can_egl_image_buffer, + gfx_ctx_init_egl_image_buffer, gfx_ctx_write_egl_image, "sdl-gl", }; diff --git a/gfx/context/vc_egl_ctx.c b/gfx/context/vc_egl_ctx.c index 030cd2bdb0..f2c5bdf4c5 100644 --- a/gfx/context/vc_egl_ctx.c +++ b/gfx/context/vc_egl_ctx.c @@ -34,6 +34,7 @@ #include #include #include +#include #include static EGLContext g_egl_ctx; @@ -46,15 +47,15 @@ static bool g_inited; static unsigned g_interval; static enum gfx_ctx_api g_api; -static unsigned g_fb_width; // Just use something for now. +static unsigned g_fb_width; static unsigned g_fb_height; -/*static EGLImageKHR eglBuffer; -static DISPMANX_RESOURCE_HANDLE_T vcBuffer; -static VC_RECT_T bufferRect; -static unsigned bufferLastWidth; -static unsigned bufferLastHeight; -static bool bufferLastRgb32; +static EGLImageKHR eglBuffer[MAX_EGLIMAGE_TEXTURES]; +static EGLContext g_eglimage_ctx; +static EGLSurface g_pbuff_surf; +static VGImage g_egl_vgimage[MAX_EGLIMAGE_TEXTURES]; +static bool g_smooth; +static unsigned g_egl_res; PFNEGLCREATEIMAGEKHRPROC peglCreateImageKHR; PFNEGLDESTROYIMAGEKHRPROC peglDestroyImageKHR; @@ -67,7 +68,7 @@ static inline bool gfx_ctx_egl_query_extension(const char *ext) ext, ret ? "exists" : "doesn't exist"); return ret; -}*/ +} static void sighandler(int sig) { @@ -236,26 +237,90 @@ 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) { + for (unsigned i = 0; i < MAX_EGLIMAGE_TEXTURES; i++) + { + 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[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) { + gfx_ctx_bind_api(g_api); eglMakeCurrent(g_egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(g_egl_dpy, g_egl_ctx); } + if (g_eglimage_ctx) + { + eglBindAPI(EGL_OPENVG_API); + eglMakeCurrent(g_egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroyContext(g_egl_dpy, g_eglimage_ctx); + } + if (g_egl_surf) + { + gfx_ctx_bind_api(g_api); eglDestroySurface(g_egl_dpy, g_egl_surf); + } + + if (g_pbuff_surf) + { + eglBindAPI(EGL_OPENVG_API); + eglDestroySurface(g_egl_dpy, g_pbuff_surf); + } + + 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); eglTerminate(g_egl_dpy); } - g_egl_ctx = NULL; - g_egl_surf = NULL; - g_egl_dpy = NULL; - g_config = 0; - g_inited = false; + g_egl_ctx = NULL; + g_eglimage_ctx = NULL; + g_egl_surf = NULL; + g_pbuff_surf = NULL; + g_egl_dpy = 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) @@ -275,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. @@ -300,48 +349,107 @@ static float gfx_ctx_translate_aspect(unsigned width, unsigned height) return (float)width / height; } -static bool gfx_ctx_can_egl_image_buffer(void) +static bool gfx_ctx_init_egl_image_buffer(const video_info_t *video) { - /*peglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)gfx_ctx_get_proc_address("eglCreateImageKHR"); + if (g_api == GFX_CTX_OPENVG_API) // don't bother, we just use VGImages for our EGLImage anyway + { + return false; + } + + peglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)gfx_ctx_get_proc_address("eglCreateImageKHR"); peglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC)gfx_ctx_get_proc_address("eglDestroyImageKHR"); - return peglCreateImageKHR && peglDestroyImageKHR && gfx_ctx_egl_query_extension("KHR_image");*/ + + if (!peglCreateImageKHR || !peglDestroyImageKHR || !gfx_ctx_egl_query_extension("KHR_image")) + { + return false; + } + + g_egl_res = video->input_scale * RARCH_SCALE_BASE; + + EGLint pbufsurface_list[] = + { + EGL_WIDTH, g_egl_res, + EGL_HEIGHT, g_egl_res, + EGL_NONE + }; + + EGLBoolean result; + + eglBindAPI(EGL_OPENVG_API); + g_pbuff_surf = eglCreatePbufferSurface(g_egl_dpy, g_config, pbufsurface_list); + if (g_pbuff_surf == EGL_NO_SURFACE) + { + RARCH_ERR("[VideoCore:EGLImage] failed to create PbufferSurface\n"); + goto fail; + } + + g_eglimage_ctx = eglCreateContext(g_egl_dpy, g_config, NULL, NULL); + if (g_eglimage_ctx == EGL_NO_CONTEXT) + { + RARCH_ERR("[VideoCore:EGLImage] failed to create context\n"); + 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) + { + RARCH_ERR("[VideoCore:EGLImage] failed to make context current\n"); + goto fail; + } + + 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) + { + eglDestroySurface(g_egl_dpy, g_pbuff_surf); + g_pbuff_surf = EGL_NO_SURFACE; + } + + if (g_eglimage_ctx != EGL_NO_CONTEXT) + { + eglDestroyContext(g_egl_dpy, g_eglimage_ctx); + g_pbuff_surf = EGL_NO_CONTEXT; + } + + gfx_ctx_bind_api(g_api); + eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx); + 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) { - /*bool ret = false; - if (!eglBuffer || !vcBuffer || (width != bufferLastWidth && height != bufferLastHeight && rgb32 != bufferLastRgb32)) + bool ret = false; + + if (index >= MAX_EGLIMAGE_TEXTURES) { - ret = true; - - if (vcBuffer) - { - vc_dispmanx_resource_delete(vcBuffer); - } - - if (eglBuffer) - { - peglDestroyImageKHR(g_egl_dpy, eglBuffer); - } - - uint32_t temp = 0xff; - vcBuffer = vc_dispmanx_resource_create((rgb32 ? VC_IMAGE_XRGB8888 : VC_IMAGE_RGB565), width, height, &temp); - rarch_assert(vcBuffer); - RARCH_LOG("temp: %08x\n", temp); - - eglBuffer = peglCreateImageKHR(g_egl_dpy, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_CLIENT_SIDE_BRCM, (EGLClientBuffer) &vcBuffer, NULL); - RARCH_ERR("ERROR: %08x\n", eglGetError()); - rarch_assert(eglBuffer); - - vc_dispmanx_rect_set(&bufferRect, 0, 0, width, height); + *image_handle = NULL; + return false; } - vc_dispmanx_resource_write_data(vcBuffer, (rgb32 ? VC_IMAGE_XRGB8888 : VC_IMAGE_RGB565), pitch, (void *)frame, &bufferRect); - *image_handle = eglBuffer; + eglBindAPI(EGL_OPENVG_API); + eglMakeCurrent(g_egl_dpy, g_pbuff_surf, g_pbuff_surf, g_eglimage_ctx); - return ret;*/ - return false; + 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); + + return ret; } const gfx_ctx_driver_t gfx_ctx_videocore = { @@ -359,7 +467,7 @@ const gfx_ctx_driver_t gfx_ctx_videocore = { gfx_ctx_swap_buffers, gfx_ctx_input_driver, gfx_ctx_get_proc_address, - gfx_ctx_can_egl_image_buffer, + gfx_ctx_init_egl_image_buffer, gfx_ctx_write_egl_image, "videocore", }; diff --git a/gfx/context/wgl_ctx.c b/gfx/context/wgl_ctx.c index b458e7e835..4358907668 100644 --- a/gfx/context/wgl_ctx.c +++ b/gfx/context/wgl_ctx.c @@ -404,12 +404,12 @@ static bool gfx_ctx_bind_api(enum gfx_ctx_api api) return api == GFX_CTX_OPENGL_API; } -static bool gfx_ctx_can_egl_image_buffer(void) +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; } @@ -429,7 +429,7 @@ const gfx_ctx_driver_t gfx_ctx_wgl = { gfx_ctx_swap_buffers, gfx_ctx_input_driver, gfx_ctx_get_proc_address, - gfx_ctx_can_egl_image_buffer, + gfx_ctx_init_egl_image_buffer, gfx_ctx_write_egl_image, "wgl", }; diff --git a/gfx/context/xdk_ctx.c b/gfx/context/xdk_ctx.c index db268579fc..40c6f654f8 100644 --- a/gfx/context/xdk_ctx.c +++ b/gfx/context/xdk_ctx.c @@ -525,12 +525,12 @@ int gfx_ctx_xdk_check_resolution(unsigned resolution_id) return 0; } -static bool gfx_ctx_can_egl_image_buffer(void) +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; } @@ -550,7 +550,7 @@ const gfx_ctx_driver_t gfx_ctx_xdk = { gfx_ctx_xdk_swap_buffers, gfx_ctx_xdk_input_driver, NULL, - gfx_ctx_can_egl_image_buffer, + gfx_ctx_init_egl_image_buffer, gfx_ctx_write_egl_image, "xdk", diff --git a/gfx/context/xegl_ctx.c b/gfx/context/xegl_ctx.c index ca03c981be..bd6a94e8f9 100644 --- a/gfx/context/xegl_ctx.c +++ b/gfx/context/xegl_ctx.c @@ -503,12 +503,12 @@ static bool gfx_ctx_bind_api(enum gfx_ctx_api api) } } -static bool gfx_ctx_can_egl_image_buffer(void) +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; } @@ -528,7 +528,7 @@ const gfx_ctx_driver_t gfx_ctx_x_egl = { gfx_ctx_swap_buffers, gfx_ctx_input_driver, gfx_ctx_get_proc_address, - gfx_ctx_can_egl_image_buffer, + gfx_ctx_init_egl_image_buffer, gfx_ctx_write_egl_image, "x-egl", }; diff --git a/gfx/gfx_context.h b/gfx/gfx_context.h index 5571bd0798..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. - bool (*can_egl_image_buffer)(void); + // 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 f39443e9b6..1c6e2364c6 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -94,13 +94,23 @@ const GLfloat *default_vertex_ptr = vertexes_flipped; memcpy(&(pgl##SYM), &sym, sizeof(sym)); \ } +#ifdef HAVE_EGL +static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC pglEGLImageTargetTexture2DOES; + +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; -static PFNGLBINDFRAMEBUFFERPROC pglBindFramebuffer = NULL; -static PFNGLFRAMEBUFFERTEXTURE2DPROC pglFramebufferTexture2D = NULL; -static PFNGLCHECKFRAMEBUFFERSTATUSPROC pglCheckFramebufferStatus = NULL; -static PFNGLDELETEFRAMEBUFFERSPROC pglDeleteFramebuffers = NULL; +static PFNGLGENFRAMEBUFFERSPROC pglGenFramebuffers; +static PFNGLBINDFRAMEBUFFERPROC pglBindFramebuffer; +static PFNGLFRAMEBUFFERTEXTURE2DPROC pglFramebufferTexture2D; +static PFNGLCHECKFRAMEBUFFERSTATUSPROC pglCheckFramebufferStatus; +static PFNGLDELETEFRAMEBUFFERSPROC pglDeleteFramebuffers; static bool load_fbo_proc(gl_t *gl) { @@ -926,22 +936,41 @@ static void gl_init_textures(gl_t *gl) static inline void gl_copy_frame(gl_t *gl, const void *frame, unsigned width, unsigned height, unsigned pitch) { #ifdef HAVE_OPENGLES2 - // No GL_UNPACK_ROW_LENGTH ;( - unsigned pitch_width = pitch / gl->base_size; - if (width == pitch_width) // Happy path :D +#ifdef HAVE_EGL + if (gl->egl_images) { - glTexSubImage2D(GL_TEXTURE_2D, - 0, 0, 0, width, height, gl->texture_type, - gl->texture_fmt, frame); + EGLImageKHR img = 0; + bool new_egl = gl->ctx_driver->write_egl_image(frame, width, height, pitch, (gl->base_size == 4), gl->tex_index, &img); + + if (img == EGL_NO_IMAGE_KHR) + { + RARCH_ERR("[GL]: Failed to create EGL image.\n"); + return; + } + + if (new_egl) + pglEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)img); } - else // Slower path. + else +#endif { - const uint8_t *src = (const uint8_t*)frame; - for (unsigned h = 0; h < height; h++, src += pitch) + // No GL_UNPACK_ROW_LENGTH ;( + unsigned pitch_width = pitch / gl->base_size; + if (width == pitch_width) // Happy path :D { glTexSubImage2D(GL_TEXTURE_2D, - 0, 0, h, width, 1, gl->texture_type, - gl->texture_fmt, src); + 0, 0, 0, width, height, gl->texture_type, + gl->texture_fmt, frame); + } + else // Slower path. + { + const uint8_t *src = (const uint8_t*)frame; + for (unsigned h = 0; h < height; h++, src += pitch) + { + glTexSubImage2D(GL_TEXTURE_2D, + 0, 0, h, width, 1, gl->texture_type, + gl->texture_fmt, src); + } } } #else @@ -957,7 +986,6 @@ static inline void gl_copy_frame(gl_t *gl, const void *frame, unsigned width, un else { glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / gl->base_size); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, gl->texture_type, gl->texture_fmt, frame); @@ -1024,6 +1052,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 +1126,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 @@ -1375,6 +1409,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 d782f0ccd1..87f60f8742 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) @@ -234,6 +237,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 acd1d9360f..13f8678445 100644 --- a/gfx/vg.c +++ b/gfx/vg.c @@ -174,7 +174,7 @@ static void *vg_init(const video_info_t *video, const input_driver_t **input, vo } #endif - if (vg_query_extension("KHR_EGL_image") && vg->driver->can_egl_image_buffer()) + if (vg_query_extension("KHR_EGL_image") && vg->driver->init_egl_image_buffer(video)) { pvgCreateEGLImageTargetKHR = (PFNVGCREATEEGLIMAGETARGETKHRPROC)vg->driver->get_proc_address("vgCreateEGLImageTargetKHR"); @@ -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", 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;