From 86fb0984d283a8daecdb5321be767fe9ef9764e7 Mon Sep 17 00:00:00 2001 From: Toad King Date: Thu, 18 Oct 2012 18:59:56 -0400 Subject: [PATCH] beginning framework for EGLImage support, added (untested) example to OpenVG --- gfx/context/androidegl_ctx.c | 12 ++++++ gfx/context/drm_egl_ctx.c | 12 ++++++ gfx/context/glx_ctx.c | 12 ++++++ gfx/context/ps3_ctx.c | 12 ++++++ gfx/context/sdl_ctx.c | 12 ++++++ gfx/context/vc_egl_ctx.c | 70 ++++++++++++++++++++++++++++++--- gfx/context/wgl_ctx.c | 12 ++++++ gfx/context/xdk_ctx.c | 10 +++++ gfx/context/xegl_ctx.c | 12 ++++++ gfx/gfx_context.h | 7 ++++ gfx/vg.c | 76 +++++++++++++++++++++++++++++++++++- 11 files changed, 241 insertions(+), 6 deletions(-) diff --git a/gfx/context/androidegl_ctx.c b/gfx/context/androidegl_ctx.c index a8025afbc3..eb5df67061 100644 --- a/gfx/context/androidegl_ctx.c +++ b/gfx/context/androidegl_ctx.c @@ -307,6 +307,16 @@ static bool gfx_ctx_has_focus(void) return true; } +bool gfx_ctx_can_egl_image_buffer(void) +{ + return false; +} + +bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, void **image_handle) +{ + return false; +} + const gfx_ctx_driver_t gfx_ctx_android = { gfx_ctx_init, gfx_ctx_destroy, @@ -322,5 +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_write_egl_image, "android", }; diff --git a/gfx/context/drm_egl_ctx.c b/gfx/context/drm_egl_ctx.c index 3d7f27f0ba..a5a7d457cd 100644 --- a/gfx/context/drm_egl_ctx.c +++ b/gfx/context/drm_egl_ctx.c @@ -625,6 +625,16 @@ static bool gfx_ctx_bind_api(enum gfx_ctx_api api) } } +bool gfx_ctx_can_egl_image_buffer(void) +{ + return false; +} + +bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, void **image_handle) +{ + return false; +} + const gfx_ctx_driver_t gfx_ctx_drm_egl = { gfx_ctx_init, gfx_ctx_destroy, @@ -640,6 +650,8 @@ 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_write_egl_image, "drm-egl", }; diff --git a/gfx/context/glx_ctx.c b/gfx/context/glx_ctx.c index 8f576fb147..28d55235de 100644 --- a/gfx/context/glx_ctx.c +++ b/gfx/context/glx_ctx.c @@ -462,6 +462,16 @@ static bool gfx_ctx_bind_api(enum gfx_ctx_api api) return api == GFX_CTX_OPENGL_API; } +bool gfx_ctx_can_egl_image_buffer(void) +{ + return false; +} + +bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, void **image_handle) +{ + return false; +} + const gfx_ctx_driver_t gfx_ctx_glx = { gfx_ctx_init, gfx_ctx_destroy, @@ -477,6 +487,8 @@ 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_write_egl_image, "glx", }; diff --git a/gfx/context/ps3_ctx.c b/gfx/context/ps3_ctx.c index a96355da90..2a61b061d5 100644 --- a/gfx/context/ps3_ctx.c +++ b/gfx/context/ps3_ctx.c @@ -378,6 +378,16 @@ static bool gfx_ctx_bind_api(enum gfx_ctx_api api) return api == GFX_CTX_OPENGL_API || GFX_CTX_OPENGL_ES_API; } +bool gfx_ctx_can_egl_image_buffer(void) +{ + return false; +} + +bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, void **image_handle) +{ + return false; +} + const gfx_ctx_driver_t gfx_ctx_ps3 = { gfx_ctx_init, gfx_ctx_destroy, @@ -393,6 +403,8 @@ 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_write_egl_image, "ps3", // RARCH_CONSOLE stuff. diff --git a/gfx/context/sdl_ctx.c b/gfx/context/sdl_ctx.c index 2f29421835..c302235281 100644 --- a/gfx/context/sdl_ctx.c +++ b/gfx/context/sdl_ctx.c @@ -316,6 +316,16 @@ static bool gfx_ctx_bind_api(enum gfx_ctx_api api) return api == GFX_CTX_OPENGL_API; } +bool gfx_ctx_can_egl_image_buffer(void) +{ + return false; +} + +bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, void **image_handle) +{ + return false; +} + const gfx_ctx_driver_t gfx_ctx_sdl_gl = { gfx_ctx_init, gfx_ctx_destroy, @@ -331,6 +341,8 @@ 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_write_egl_image, "sdl-gl", }; diff --git a/gfx/context/vc_egl_ctx.c b/gfx/context/vc_egl_ctx.c index 8b9cb9806e..6bde808750 100644 --- a/gfx/context/vc_egl_ctx.c +++ b/gfx/context/vc_egl_ctx.c @@ -33,6 +33,7 @@ #include #include +#include #include static EGLContext g_egl_ctx; @@ -48,11 +49,25 @@ static enum gfx_ctx_api g_api; static unsigned g_fb_width; // Just use something for now. static unsigned g_fb_height; -struct drm_fb +/*static EGLImageKHR eglBuffer; +static DISPMANX_RESOURCE_HANDLE_T vcBuffer; +static VC_RECT_T bufferRect; +static unsigned bufferLastWidth; +static unsigned bufferLastHeight; +static bool bufferLastRgb32; + +PFNEGLCREATEIMAGEKHRPROC peglCreateImageKHR; +PFNEGLDESTROYIMAGEKHRPROC peglDestroyImageKHR; + +static inline bool gfx_ctx_egl_query_extension(const char *ext) { - struct gbm_bo *bo; - uint32_t fb_id; -}; + const char *str = (const char*)eglQueryString(g_egl_dpy, EGL_EXTENSIONS); + bool ret = str && strstr(str, ext); + RARCH_LOG("Querying EGL extension: %s => %s\n", + ext, ret ? "exists" : "doesn't exist"); + + return ret; +}*/ static void sighandler(int sig) { @@ -285,6 +300,50 @@ static float gfx_ctx_translate_aspect(unsigned width, unsigned height) return (float)width / height; } +bool gfx_ctx_can_egl_image_buffer(void) +{ + /*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");*/ + return false; +} + +bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, void **image_handle) +{ + /*bool ret = false; + if (!eglBuffer || !vcBuffer || (width != bufferLastWidth && height != bufferLastHeight && rgb32 != bufferLastRgb32)) + { + 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); + } + + vc_dispmanx_resource_write_data(vcBuffer, (rgb32 ? VC_IMAGE_XRGB8888 : VC_IMAGE_RGB565), pitch, (void *)frame, &bufferRect); + *image_handle = eglBuffer; + + return ret;*/ + return false; +} + const gfx_ctx_driver_t gfx_ctx_videocore = { gfx_ctx_init, gfx_ctx_destroy, @@ -300,6 +359,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_write_egl_image, "videocore", }; - diff --git a/gfx/context/wgl_ctx.c b/gfx/context/wgl_ctx.c index 8469bee9d7..55c20f5912 100644 --- a/gfx/context/wgl_ctx.c +++ b/gfx/context/wgl_ctx.c @@ -404,6 +404,16 @@ static bool gfx_ctx_bind_api(enum gfx_ctx_api api) return api == GFX_CTX_OPENGL_API; } +bool gfx_ctx_can_egl_image_buffer(void) +{ + return false; +} + +bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, void **image_handle) +{ + return false; +} + const gfx_ctx_driver_t gfx_ctx_wgl = { gfx_ctx_init, gfx_ctx_destroy, @@ -419,6 +429,8 @@ 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_write_egl_image, "wgl", }; diff --git a/gfx/context/xdk_ctx.c b/gfx/context/xdk_ctx.c index 6a734110db..be6282d57d 100644 --- a/gfx/context/xdk_ctx.c +++ b/gfx/context/xdk_ctx.c @@ -525,7 +525,15 @@ int gfx_ctx_xdk_check_resolution(unsigned resolution_id) return 0; } +bool gfx_ctx_can_egl_image_buffer(void) +{ + return false; +} +bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, void **image_handle) +{ + return false; +} const gfx_ctx_driver_t gfx_ctx_xdk = { gfx_ctx_xdk_init, @@ -542,6 +550,8 @@ 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_write_egl_image, "xdk", // RARCH_CONSOLE stuff. diff --git a/gfx/context/xegl_ctx.c b/gfx/context/xegl_ctx.c index eb4c15a055..80c1b81c79 100644 --- a/gfx/context/xegl_ctx.c +++ b/gfx/context/xegl_ctx.c @@ -503,6 +503,16 @@ static bool gfx_ctx_bind_api(enum gfx_ctx_api api) } } +bool gfx_ctx_can_egl_image_buffer(void) +{ + return false; +} + +bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, void **image_handle) +{ + return false; +} + const gfx_ctx_driver_t gfx_ctx_x_egl = { gfx_ctx_init, gfx_ctx_destroy, @@ -518,6 +528,8 @@ 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_write_egl_image, "x-egl", }; diff --git a/gfx/gfx_context.h b/gfx/gfx_context.h index 2cc0b8690a..5571bd0798 100644 --- a/gfx/gfx_context.h +++ b/gfx/gfx_context.h @@ -80,6 +80,13 @@ 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); + + // 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); + // Human readable string. const char *ident; diff --git a/gfx/vg.c b/gfx/vg.c index cdb59652a2..acd1d9360f 100644 --- a/gfx/vg.c +++ b/gfx/vg.c @@ -16,12 +16,15 @@ #include #include +#include #include +#include #include "gfx_context.h" #include "math/matrix_3x3.h" #include "../libretro.h" #include "../general.h" #include "../driver.h" +#include "../benchmark.h" #ifdef HAVE_FREETYPE #include "fonts/fonts.h" @@ -36,6 +39,7 @@ typedef struct bool should_resize; float mScreenAspect; bool mKeepAspect; + bool mEglImageBuf; unsigned mTextureWidth; unsigned mTextureHeight; unsigned mRenderWidth; @@ -46,6 +50,7 @@ typedef struct VGImage mImage; math_matrix_3x3 mTransformMatrix; VGint scissor[4]; + EGLImageKHR last_egl_image; #ifdef HAVE_FREETYPE char *mLastMsg; @@ -60,12 +65,24 @@ typedef struct #endif } vg_t; +static PFNVGCREATEEGLIMAGETARGETKHRPROC pvgCreateEGLImageTargetKHR; + static void vg_set_nonblock_state(void *data, bool state) { vg_t *vg = (vg_t*)data; vg->driver->swap_interval(state ? 0 : 1); } +static inline bool vg_query_extension(const char *ext) +{ + const char *str = (const char*)vgGetString(VG_EXTENSIONS); + bool ret = str && strstr(str, ext); + RARCH_LOG("Querying VG extension: %s => %s\n", + ext, ret ? "exists" : "doesn't exist"); + + return ret; +} + static void *vg_init(const video_info_t *video, const input_driver_t **input, void **input_data) { vg_t *vg = (vg_t*)calloc(1, sizeof(vg_t)); @@ -157,6 +174,23 @@ 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()) + { + pvgCreateEGLImageTargetKHR = (PFNVGCREATEEGLIMAGETARGETKHRPROC)vg->driver->get_proc_address("vgCreateEGLImageTargetKHR"); + + if (pvgCreateEGLImageTargetKHR) + { + RARCH_LOG("[VG] Using EGLImage buffer\n"); + vg->mEglImageBuf = true; + } + } + +#if 0 + const char *ext = (const char*)vgGetString(VG_EXTENSIONS); + if (ext) + RARCH_LOG("[VG] Supported extensions: %s\n", ext); +#endif + return vg; } @@ -309,8 +343,40 @@ static void vg_calculate_quad(vg_t *vg) vgSetiv(VG_SCISSOR_RECTS, 4, vg->scissor); } +static void vg_copy_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch) +{ + vg_t *vg = (vg_t*)data; + + if (vg->mEglImageBuf) + { + EGLImageKHR img = 0; + bool new_egl = vg->driver->write_egl_image(frame, width, height, pitch, (vg->mTexType == VG_sXRGB_8888), &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()); + exit(2); + } + vg->last_egl_image = img; + } + } + else + { + vgImageSubData(vg->mImage, frame, pitch, vg->mTexType, 0, 0, width, height); + } +} + static bool vg_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg) { + + RARCH_PERFORMANCE_INIT(vg_fr); + RARCH_PERFORMANCE_START(vg_fr); vg_t *vg = (vg_t*)data; vg->frame_count++; @@ -333,7 +399,12 @@ static bool vg_frame(void *data, const void *frame, unsigned width, unsigned hei vgClear(0, 0, vg->mScreenWidth, vg->mScreenHeight); vgSeti(VG_SCISSORING, VG_TRUE); - vgImageSubData(vg->mImage, frame, pitch, vg->mTexType, 0, 0, width, height); + RARCH_PERFORMANCE_INIT(vg_image); + RARCH_PERFORMANCE_START(vg_image); + vg_copy_frame(vg, frame, width, height, pitch); + RARCH_PERFORMANCE_STOP(vg_image); + RARCH_PERFORMANCE_LOG("vg_copy_frame", vg_image); + vgDrawImage(vg->mImage); #ifdef HAVE_FREETYPE @@ -343,6 +414,9 @@ static bool vg_frame(void *data, const void *frame, unsigned width, unsigned hei (void)msg; #endif + RARCH_PERFORMANCE_STOP(vg_fr); + RARCH_PERFORMANCE_LOG("vg_frame", vg_fr); + vg->driver->swap_buffers(); return true;