Tizen Native API
5.0
|
Defines | |
#define | ELEMENTARY_GLVIEW_USE(glview) Evas_GL_API *__evas_gl_glapi = elm_glview_gl_api_get(glview); |
Convenience macro to insert at the beginning of every function calling OpenGL with GLView. | |
#define | ELEMENTARY_GLVIEW_USE_OR_RETURN(glview, retval) |
Convenience macro to insert at the beginning of every function calling OpenGL with GLView. | |
#define | ELEMENTARY_GLVIEW_GLOBAL_DECLARE() extern Evas_GL_API *__evas_gl_glapi; |
Convenience macro to use the GL helpers in simple applications: declare. | |
#define | ELEMENTARY_GLVIEW_GLOBAL_DEFINE() Evas_GL_API *__evas_gl_glapi = NULL; |
Convenience macro to use the GL helpers in simple applications: define. | |
#define | ELEMENTARY_GLVIEW_GLOBAL_USE(glview) do { __evas_gl_glapi = elm_glview_gl_api_get(glview); } while (0) |
Convenience macro to use the GL helpers in simple applications: use. | |
#define | ELEMENTARY_GLVIEW_GLES1_API_CHECK() EVAS_GL_GLES1_API_CHECK() |
Macro to check that the GL APIs are properly set (GLES 1.1) | |
#define | ELEMENTARY_GLVIEW_GLES2_API_CHECK() EVAS_GL_GLES2_API_CHECK() |
Macro to check that the GL APIs are properly set (GLES 2.0) | |
#define | ELEMENTARY_GLVIEW_GLES3_API_CHECK() EVAS_GL_GLES3_API_CHECK() |
Macro to check that the GL APIs are properly set (GLES 3.0) |
Contents of this section:
While Evas and Ecore provide all the required functions to build a whole application based on EFL and using OpenGL, it is recommended to use GLView instead. Elementary GLView will create a drawable GL surface for the application, and set up all the required callbacks so that the complexity of Evas GL is hidden.
The file Elementary_GL_Helpers.h provides some convenience functions that ease the use of OpenGL within an Elementary application.
Evas GL is an abstraction layer on top of EGL, GLX or WGL that should provide the necessary features for most applications, in a platform-independent way. Since the goal of Evas GL is to abstract the underlying platform, only a subset of the features can be used by applications.
On top of this, an Evas GL surface can be stacked within a GUI layout just like any other widget, and will support transparency, direct rendering, and various other features. For these reasons, it is not possible to directly expose lower level APIs like OpenGL or EGL and interact with Evas as the same time.
The following sections should provide developers guides on how to use OpenGL-ES in an EFL application.
When using GLView, EFL will take care of the tedious creation of all the surfaces and contexts. Also, EFL hides the underlying display system so there is no way to get a direct handle to
Here is a demo using EFL with OpenGL:
// gcc `pkg-config --cflags --libs elementary` glview.c -o glview #include <Elementary_GL_Helpers.h> static void _draw_gl(Evas_Object *obj) { ELEMENTARY_GLVIEW_USE(obj); glClearColor(0.2, 0.2, 0.2, 1.0); glClear(GL_COLOR_BUFFER_BIT); } static void _resize_gl(Evas_Object *obj) { ELEMENTARY_GLVIEW_USE(obj); int w, h; elm_glview_size_get(obj, &w, &h); glViewport(0, 0, w, h); } // This is the GL initialization function Evas_Object* glview_create(Evas_Object *win) { Evas_Object *glview; glview = elm_glview_add(win); elm_win_resize_object_add(win, glview); elm_glview_mode_set(glview, ELM_GLVIEW_ALPHA | ELM_GLVIEW_DEPTH | ELM_GLVIEW_STENCIL); elm_glview_resize_policy_set(glview, ELM_GLVIEW_RESIZE_POLICY_RECREATE); elm_glview_render_policy_set(glview, ELM_GLVIEW_RENDER_POLICY_ON_DEMAND); //elm_glview_init_func_set(glview, _init_gl); //elm_glview_del_func_set(glview, _del_gl); elm_glview_render_func_set(glview, _draw_gl); elm_glview_resize_func_set(glview, _resize_gl); evas_object_size_hint_min_set(glview, 250, 250); evas_object_show(glview); return glview; } EAPI int elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED) { Evas_Object *win; // Set the acceleration preference to 3d elm_config_accel_preference_set("3d"); // Create a window win = elm_win_util_standard_add("glview", "GLView"); evas_object_show(win); // Setup our GLView glview_create(win); elm_run(); elm_shutdown(); return 0; } ELM_MAIN()
Evas GL can be used to render directly to the back buffer of the Evas window. It is important to note that this is an optimization path and this will present a few limitations. Normally, Evas GL will create an FBO and use it as target surface for all the GL draw operations, and finally blend this FBO's contents to the Evas canvas.
Evas GL will automatically fallback to indirect rendering unless the conditions are right. The flag EVAS_GL_OPTIONS_DIRECT must be set on the target surface in order to enable direct rendering. When using the Elementary GLView widget, the flag ELM_GLVIEW_DIRECT
should be set.
Some limitations of direct rendering include the following:
glClear()
is called after glClearColor(0,0,0,0)
, then clear will be skipped for the color buffer. Otherwise this would erase the back buffer in evas, instead of preparing a transparent surface for GL rendering. Opaque colors will be cleared as expected (eg.
(0,0,0,1)). Since Tizen 2.3, Evas GL supports the OpenGL-ES 1.1 set of rendering APIs on top of the normal OpenGL-ES 2.0 APIs, if the drivers supports it.
With GLView, it is easy to create a 1.1 capable surface:
Evas_Object *glview; glview = elm_glview_version_add(win, EVAS_GL_GLES_1_X);
Since Tizen 2.4, Evas GL supports the OpenGL-ES 3.0 set of rendering APIs on top of the normal OpenGL-ES 2.0 APIs, if the drivers supports it.
With GLView, it is easy to create a 3.0 capable surface:
Evas_Object *glview; glview = elm_glview_version_add(win, EVAS_GL_GLES_3_X);
As usual, the GL API is available using elm_glview_gl_api_get, which can be abstracted with ELEMENTARY_GLVIEW_USE.
When using Evas GL directly, developers must be careful to use evas_gl_context_api_get with the current context in order to get the proper API (1.1 or 2.0 or 3.0). Indeed, evas_gl_api_get will always return a GLES 2.0 API, and the 1.1 and 2.0 APIs are not compatible. Also, the application will then be responsible for calling evas_gl_make_current
.
Of course, Evas GL is not limited to creating fullscreen OpenGL target surfaces, and some developers might want to exploit some of the more advanced features of Evas GL.
These features usually require to use Rendering GL on Evas directly rather than just GLView.
As explained above, Evas GL is an abstraction layer on top of EGL, but not limited to EGL. While trying to look similar to EGL, Evas GL should also support GLX and other backends (WGL, ...).
As a consequence, only a subset of the EGL features are supported by Evas GL.
Manual work is required in order to transform all calls to EGL into Evas GL calls, but the final code should be much lighter when using EFL. Here is a simple table comparison between EGL and Evas GL calls:
EGL | Evas GL | Comment |
---|---|---|
eglGetDisplay | N/A | Not required |
eglInitialize | evas_gl_new | - |
eglTerminate | evas_gl_free | - |
eglQueryString | evas_gl_string_query | For extensions: if (glapi->evasglExtFunc) { ... } |
eglReleaseThread | N/A | - |
eglGetConfigs | N/A | Not required |
eglGetConfigAttrib | N/A | - |
eglChooseConfig | evas_gl_config_new and Evas_GL_Config | - |
eglCreateWindowSurface | GLView or evas_gl_surface_create | GLView provides elm_glview_add |
eglCreatePixmapSurface | N/A | Not available because it is platform dependent |
eglCreatePbufferSurface | evas_gl_pbuffer_surface_create | - |
eglCreatePbufferFromClientBuffer | N/A | - |
eglDestroySurface | evas_gl_surface_destroy | - |
eglSurfaceAttrib | N/A | Surfaces can't be changed |
eglQuerySurface | evas_gl_surface_query | Subset of features only |
eglCreateContext | evas_gl_context_create and evas_gl_context_version_create | GLView provides elm_glview_add |
eglDestroyContext | evas_gl_context_destroy | - |
eglMakeCurrent | evas_gl_make_current | - |
eglWaitGL | N/A | Use a fence sync if available |
eglWaitNative | N/A | Use a fence sync if available |
eglWaitClient | N/A | Use a fence sync if available |
eglSwapBuffers | N/A | Transparently done by Evas |
eglCopyBuffers | N/A | Not available because it is platform dependent |
eglSwapInterval | N/A | Transparently done by Ecore and Evas |
eglBindTexImage | N/A | Not available, use FBOs |
eglReleaseTexImage | N/A | Not available, use FBOs |
eglGetProcAddress | Evas_GL_API: evas_gl_proc_address_get | Provides extra Evas GL extensions (not EGL) |
eglCreateImageKHR | Evas_GL_API: evasglCreateImageForContext | Extension |
eglDestroyImageKHR | Evas_GL_API:evasglDestroyImage | Extension |
eglCreateSyncKHR | Evas_GL_API: evasglCreateSync | Extension |
eglDestroySyncKHR | Evas_GL_API: evasglDestroySync | Extension |
eglClientWaitSyncKHR | Evas_GL_API: evasglClientWaitSync | Extension |
eglSignalSyncKHR | Evas_GL_API: evasglSignalSync | Extension |
eglGetSyncAttribKHR | Evas_GL_API: evasglGetSyncAttrib | Extension |
eglWaitSyncKHR | Evas_GL_API: evasglWaitSync | Extension |
The extensions above may or may not be available depending on the OpenGL driver and the backend used.
Some EGL definitions have also been imported and transformed for Evas GL. In particular, the EVAS_GL error codes returned by evas_gl_error_get don't start from 0x3000
like EGL but from 0. Also, attribute lists can be terminated by 0 instead of EGL_NONE
.
When using EGL, it is common to query a surface for its properties. Evas GL supports only a subset of the surface properties:
Refer to evas_gl_surface_query for more information.
If an application wants to render offscreen using OpenGL, it can use FBOs. But if the application wants to render in a separate render thread, a surface must be created for that thread in order to call evas_gl_make_current.
In the EGL world, it is common to create a PBuffer surface with eglCreatePBufferSurface()
and set its size to 1x1. With Rendering GL on Evas this is possible using evas_gl_pbuffer_surface_create.
Here is how an application could setup a render context in a separate thread:
// In the init function: Evas_GL_Surface *sfc; Evas_GL_Config *cfg; Evas_GL_Context *ctx; Evas_GL *evasgl; evasgl = elm_glview_evas_gl_get(glview); cfg = evas_gl_config_new(); cfg->color_format = EVAS_GL_RGBA_8888; cfg->depth_bits = EVAS_GL_DEPTH_NONE; cfg->stencil_bits = EVAS_GL_STENCIL_NONE; cfg->options_bits = EVAS_GL_OPTIONS_NONE; sfc = evas_gl_pbuffer_surface_create(evasgl, cfg, WIDTH, HEIGHT, NULL); ctx = evas_gl_context_create(elm_glview_evas_gl_get(glview), NULL); evas_gl_config_free(cfg); // ... // In the render function: evas_gl_make_current(evasgl, sfc, ctx); // Render to a FBO, bind it to a native image and pass it to the main thread // using an EvasGLImage.
Multithread OpenGL rendering with Evas GL is the topic of another guide.
#define ELEMENTARY_GLVIEW_GLES1_API_CHECK | ( | ) | EVAS_GL_GLES1_API_CHECK() |
Macro to check that the GL APIs are properly set (GLES 1.1)
#define ELEMENTARY_GLVIEW_GLES2_API_CHECK | ( | ) | EVAS_GL_GLES2_API_CHECK() |
Macro to check that the GL APIs are properly set (GLES 2.0)
#define ELEMENTARY_GLVIEW_GLES3_API_CHECK | ( | ) | EVAS_GL_GLES3_API_CHECK() |
Macro to check that the GL APIs are properly set (GLES 3.0)
#define ELEMENTARY_GLVIEW_GLOBAL_DECLARE | ( | ) | extern Evas_GL_API *__evas_gl_glapi; |
Convenience macro to use the GL helpers in simple applications: declare.
This second set of helper macros can be used in simple applications that use OpenGL with a single target surface.
ELEMENTARY_GLVIEW_GLOBAL_DECLARE
should be used in a global header for the application. For example, in a platform-specific compatibility header file.main.h:
#include <Elementary_GL_Helpers.h> // other includes... ELEMENTARY_GLVIEW_GLOBAL_DECLARE() // ...
#define ELEMENTARY_GLVIEW_GLOBAL_DEFINE | ( | ) | Evas_GL_API *__evas_gl_glapi = NULL; |
Convenience macro to use the GL helpers in simple applications: define.
ELEMENTARY_GLVIEW_GLOBAL_DEFINE
should be used at the top of a file creating the GLView widget.
Example of a file glview.c:
#include "main.h" ELEMENTARY_GLVIEW_GLOBAL_DEFINE() // ... static Evas_Object * glview_create(Evas_Object *parent) { Evas_Object *glview; glview = elm_glview_version_add(parent, EVAS_GL_GLES_2_X); ELEMENTARY_GLVIEW_GLOBAL_USE(glview); elm_glview_mode_set(glview, ELM_GLVIEW_ALPHA | ELM_GLVIEW_DEPTH | ELM_GLVIEW_STENCIL); elm_glview_resize_policy_set(glview, ELM_GLVIEW_RESIZE_POLICY_RECREATE); elm_glview_render_policy_set(glview, ELM_GLVIEW_RENDER_POLICY_ON_DEMAND); elm_glview_init_func_set(glview, _init_gl); elm_glview_del_func_set(glview, _del_gl); elm_glview_resize_func_set(glview, _resize_gl); elm_glview_render_func_set(glview, _draw_gl); return glview; } // ...
#define ELEMENTARY_GLVIEW_GLOBAL_USE | ( | glview | ) | do { __evas_gl_glapi = elm_glview_gl_api_get(glview); } while (0) |
Convenience macro to use the GL helpers in simple applications: use.
This macro will set the global variable holding the GL API so that it's available to the application.
It should be used right after setting up the GLView object.
#define ELEMENTARY_GLVIEW_USE | ( | glview | ) | Evas_GL_API *__evas_gl_glapi = elm_glview_gl_api_get(glview); |
Convenience macro to insert at the beginning of every function calling OpenGL with GLView.
[in] | glview | Elementary GLView object in use |
Here's a very simple code example:
static void _draw_gl(Evas_Object *obj) { ELEMENTARY_GLVIEW_USE(obj); glClearColor(0.2, 0.2, 0.2, 1.0); glClear(GL_COLOR_BUFFER_BIT); }
This is the equivalent of:
static void _draw_gl(Evas_Object *obj) { Evas_GL_API *api = elm_glview_gl_api_get(obj); api->glClearColor(0.2, 0.2, 0.2, 1.0); api->glClear(GL_COLOR_BUFFER_BIT); }
#define ELEMENTARY_GLVIEW_USE_OR_RETURN | ( | glview, | |
retval | |||
) |
Evas_GL_API *__evas_gl_glapi = elm_glview_gl_api_get(glview); \ if (!__evas_gl_glapi) return retval;
Convenience macro to insert at the beginning of every function calling OpenGL with GLView.
[in] | glview | Elementary GLView object in use |
[in] | retval | A value to return in case of failure (GL API was not found), can be empty |
This is similar to ELEMENTARY_GLVIEW_USE except that it will return from the function if the GL API can not be used.