Tizen Native API
7.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 Elm_GLView. | |
#define | ELEMENTARY_GLVIEW_USE_OR_RETURN(glview, retval) |
Convenience macro to insert at the beginning of every function calling OpenGL with Elm_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) |
OpenGL with Elementary
Porting a native EGL+OpenGL-ES2 application to EFL
Contents of this section:
- Foreword
- Why all the trouble?
- Evas GL initialization with GLView
- Direct rendering with Evas GL
- OpenGL-ES 1.1 support in EFL
- Other uses of EGL and their Evas GL equivalents
Foreword
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 Elm_GLView instead. Elementary Elm_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.
Convenience functions for OpenGL with EFL
The file Elementary_GL_Helpers.h provides some convenience functions that ease the use of OpenGL within an Elementary application.
Why all the trouble?
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.
Evas GL initialization with GLView
When using Elm_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()
Direct rendering with Evas GL
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:
- If
glClear()
is called afterglClearColor(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)).
- Evas GL will fallback to indirect rendering if an Evas Map is applied, or if other conditions force Evas to fallback.
- The user application is responsible for handling screen rotation when using direct rendering, which is why applications should set the flag EVAS_GL_OPTIONS_CLIENT_SIDE_ROTATION on the GL surface (or ELM_GLVIEW_CLIENT_SIDE_ROTATION for Elm_GLView). Please also see evas_gl_rotation_get.
- Note:
- Direct rendering is an option that can drastically improve the performance of OpenGL applications, but it can exhibit some side effects.
OpenGL-ES 1.1 support in EFL
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 Elm_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);
OpenGL-ES 3.0 support in EFL
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 Elm_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
.
- Remarks:
- Always use Elm_GLView unless there is a very good reason not to.
Other uses of EGL and their Evas GL equivalents
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 Elm_GLView.
Evas GL vs. EGL
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 | Elm_GLView or evas_gl_surface_create | Elm_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 | Elm_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
.
Query surfaces for their properties
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.
PBuffer surfaces for multithread rendering
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 Documentation
#define ELEMENTARY_GLVIEW_GLES1_API_CHECK | ( | ) | EVAS_GL_GLES1_API_CHECK() |
Macro to check that the GL APIs are properly set (GLES 1.1)
- Since :
- 2.3
#define ELEMENTARY_GLVIEW_GLES2_API_CHECK | ( | ) | EVAS_GL_GLES2_API_CHECK() |
Macro to check that the GL APIs are properly set (GLES 2.0)
- Since :
- 2.3
#define ELEMENTARY_GLVIEW_GLES3_API_CHECK | ( | ) | EVAS_GL_GLES3_API_CHECK() |
Macro to check that the GL APIs are properly set (GLES 3.0)
- Since :
- 2.4
#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.
- Warning:
- Be very careful when using these macros! The only recommended solution is to use ELEMENTARY_GLVIEW_USE in every client function. Here are some situations where you should not use the global helpers:
- If you are using more than one Evas canvas at a time (eg. multiple windows). The GL API will be different if you are using different rendering engines (software and GL for instance), and this can happen as soon as you have multiple canvases.
- If you are using multiple GLES APIs i.e OpenGL-ES 1.1, OpenGL-ES 2.0 and OpenGL-ES 3.0 APIs.
- If you are writing or porting a library that may be used by other applications.
- Only one surface is used for GL rendering,
- Only one API set (GLES 1.1 or GLES 2.0 or GLES 3.0) is used
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() // ...
- Since :
- 2.3
#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 Elm_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; } // ...
- Since :
- 2.3
#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 Elm_GLView object.
- Since :
- 2.3
#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 Elm_GLView.
- Parameters:
-
[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); }
- Note:
- This macro should be used in every function that calls OpenGL from the Elementary. This indeed means that each function must have access to the Elm_GLView widget. Although this might require some changes in existing GL codebases, this is the recommended way to use the GL API.
- Since :
- 2.3
#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 Elm_GLView.
- Parameters:
-
[in] glview Elementary Elm_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.
- Since :
- 2.3