tizen 2.3.1 release
[framework/graphics/cairo.git] / src / cairo-evas-gl-context.c
1 /* cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2009 Eric Anholt
4  * Copyright © 2009 Chris Wilson
5  * Copyright © 2005 Red Hat, Inc
6  * Copyright © 2014 Samsung Research America, Inc - Silicon Valley
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it either under the terms of the GNU Lesser General Public
10  * License version 2.1 as published by the Free Software Foundation
11  * (the "LGPL") or, at your option, under the terms of the Mozilla
12  * Public License Version 1.1 (the "MPL"). If you do not alter this
13  * notice, a recipient may use your version of this file under either
14  * the MPL or the LGPL.
15  *
16    You should have received a copy of the LGPL along with this library
17  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19  * You should have received a copy of the MPL along with this library
20  * in the file COPYING-MPL-1.1
21  *
22  * The contents of this file are subject to the Mozilla Public License
23  * Version 1.1 (the "License"); you may not use this file except in
24  * compliance with the License. You may obtain a copy of the License at
25  * http://www.mozilla.org/MPL/
26  *
27  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29  * the specific language governing rights and limitations.
30  *
31  * The Original Code is the cairo graphics library.
32  *
33  * The Initial Developer of the Original Code is Red Hat, Inc.
34  *
35  * Contributor(s):
36  *      Carl Worth <cworth@cworth.org>
37  *      Chris Wilson <chris@chris-wilson.co.uk>
38  *      Henry Song <henry.song@samsung.com>
39  */
40
41 #include "cairoint.h"
42 #include "cairo-gl-private.h"
43 #include "cairo-error-private.h"
44 #if CAIRO_HAS_DLSYM
45 #include <dlfcn.h>
46 #endif
47
48 #include "cairo-evas-gl.h"
49
50 typedef struct _cairo_evas_gl_context {
51     cairo_gl_context_t base;
52
53     Evas_GL *evas_gl;
54     Evas_GL_Surface *surface;
55     Evas_GL_Context *context;
56
57     Evas_GL_Surface *dummy_surface;
58     Evas_GL_Surface *current_surface;
59
60     Evas_GL_Context *queried_context;
61
62     cairo_bool_t has_multithread_makecurrent;
63 } cairo_evas_gl_context_t;
64
65 typedef struct _cairo_evas_gl_surface {
66     cairo_gl_surface_t base;
67
68     Evas_GL_Surface *surface;
69 } cairo_evas_gl_surface_t;
70
71 /* as of efl-1.12.0, the following GL functions are supported, for other
72    GL functions and extensions, we us dlsym to get.
73
74    The following APIs are not supported by efl-1.12
75    glDrawBuffer, glReadBuffer, glMapBuffer, glUnmapBuffer,
76    glBlitFramebuffer{ANGLE}, glRenderbufferStorageMultisample{ANGLE},
77
78    This functions are queried via dlsym.  cairo does not use map/unmap
79    buffer.  For rest unsupported GL functions, they should not change
80    evas_gl internal context states (I hope).
81  */
82 static cairo_gl_generic_func_t
83 _cairo_evas_gl_get_proc_addr (void *data, const char *name)
84 {
85     static Evas_GL_API *api;
86     Evas_GL *gl = (Evas_GL *) data;
87     int i;
88
89     struct {
90         size_t func;
91         const char *name;
92     } evas_gl_func_map[] = {
93         /* core function, glReadBuffer and glDrawBuffer not supported */
94         { offsetof (Evas_GL_API, glActiveTexture        ), "glActiveTexture" },
95         { offsetof (Evas_GL_API, glBindTexture          ), "glBindTexture" },
96         { offsetof (Evas_GL_API, glBlendFunc            ), "glBlendFunc" },
97         { offsetof (Evas_GL_API, glBlendFuncSeparate    ), "glBlendFuncSeparate" },
98         { offsetof (Evas_GL_API, glClear                ), "glClear" },
99         { offsetof (Evas_GL_API, glClearColor           ), "glClearColor" },
100         { offsetof (Evas_GL_API, glClearStencil         ), "glClearStencil" },
101         { offsetof (Evas_GL_API, glColorMask            ), "glColorMask" },
102         { offsetof (Evas_GL_API, glDeleteTextures       ), "glDeleteTextures" },
103         { offsetof (Evas_GL_API, glDepthMask            ), "glDepthMask" },
104         { offsetof (Evas_GL_API, glDisable              ), "glDisable" },
105         { offsetof (Evas_GL_API, glDrawArrays           ), "glDrawArrays" },
106         { offsetof (Evas_GL_API, glDrawElements         ), "glDrawElements" },
107         { offsetof (Evas_GL_API, glEnable               ), "glEnable" },
108         { offsetof (Evas_GL_API, glGenTextures          ), "glGenTextures" },
109         { offsetof (Evas_GL_API, glGetBooleanv          ), "glGetBooleanv" },
110         { offsetof (Evas_GL_API, glGetError             ), "glGetError" },
111         { offsetof (Evas_GL_API, glGetFloatv            ), "glGetFloatv" },
112         { offsetof (Evas_GL_API, glGetIntegerv          ), "glGetIntegerv" },
113         { offsetof (Evas_GL_API, glGetString            ), "glGetString" },
114         { offsetof (Evas_GL_API, glPixelStorei          ), "glPixelStorei" },
115         { offsetof (Evas_GL_API, glReadPixels           ), "glReadPixels" },
116         { offsetof (Evas_GL_API, glScissor              ), "glScissor" },
117         { offsetof (Evas_GL_API, glStencilFunc          ), "glStencilFunc" },
118         { offsetof (Evas_GL_API, glStencilMask          ), "glStencilMask" },
119         { offsetof (Evas_GL_API, glStencilOp            ), "glStencilOp" },
120         { offsetof (Evas_GL_API, glTexImage2D           ), "glTexImage2D" },
121         { offsetof (Evas_GL_API, glTexSubImage2D        ), "glTexSubImage2D" },
122         { offsetof (Evas_GL_API, glTexParameteri        ), "glTexParameteri" },
123         { offsetof (Evas_GL_API, glViewport             ), "glViewport" },
124         /* buffers functions, glMapBufferOES, glUnmapBufferOES not
125            suported
126          */
127         { offsetof (Evas_GL_API, glGenBuffers           ), "glGenBuffers" },
128         { offsetof (Evas_GL_API, glBindBuffer           ), "glBindBuffer" },
129         { offsetof (Evas_GL_API, glBufferData           ), "glBufferData" },
130         /* shader functions */
131         { offsetof (Evas_GL_API, glCreateShader         ), "glCreateShader" },
132         { offsetof (Evas_GL_API, glShaderSource         ), "glShaderSource" },
133         { offsetof (Evas_GL_API, glCompileShader        ), "glCompileShader" },
134         { offsetof (Evas_GL_API, glGetShaderiv          ), "glGetShaderiv" },
135         { offsetof (Evas_GL_API, glGetShaderInfoLog     ), "glGetShaderInfoLog" },
136         { offsetof (Evas_GL_API, glDeleteShader         ), "glDeleteShader" },
137         /* program functions */
138         { offsetof (Evas_GL_API, glCreateProgram        ), "glCreateProgram" },
139         { offsetof (Evas_GL_API, glAttachShader         ), "glAttachShader" },
140         { offsetof (Evas_GL_API, glDeleteProgram        ), "glDeleteProgram" },
141         { offsetof (Evas_GL_API, glLinkProgram          ), "glLinkProgram" },
142         { offsetof (Evas_GL_API, glUseProgram           ), "glUseProgram" },
143         { offsetof (Evas_GL_API, glGetProgramiv         ), "glGetProgramiv" },
144         { offsetof (Evas_GL_API, glGetProgramInfoLog    ), "glGetProgramInfoLog" },
145         /* uniform functions */
146         { offsetof (Evas_GL_API, glGetUniformLocation   ), "glGetUniformLocation" },
147         { offsetof (Evas_GL_API, glUniform1f            ), "glUniform1f" },
148         { offsetof (Evas_GL_API, glUniform2f            ), "glUniform2f" },
149         { offsetof (Evas_GL_API, glUniform3f            ), "glUniform3f" },
150         { offsetof (Evas_GL_API, glUniform4f            ), "glUniform4f" },
151         { offsetof (Evas_GL_API, glUniform1fv           ), "glUniform1fv" },
152         { offsetof (Evas_GL_API, glUniformMatrix3fv     ), "glUniformMatrix3fv" },
153         { offsetof (Evas_GL_API, glUniformMatrix4fv     ), "glUniformMatrix4fv" },
154         { offsetof (Evas_GL_API, glUniform1i            ), "glUniform1i" },
155         /* attribute functions */
156         { offsetof (Evas_GL_API, glBindAttribLocation   ), "glBindAttribLocation" },
157         { offsetof (Evas_GL_API, glVertexAttribPointer  ), "glVertexAttribPointer" },
158         { offsetof (Evas_GL_API, glEnableVertexAttribArray), "glEnableVertexAttribArray" },
159         { offsetof (Evas_GL_API, glDisableVertexAttribArray), "glDisableVertexAttribArray" },
160         /* fbo functions */
161         { offsetof (Evas_GL_API, glGenFramebuffers      ), "glGenFramebuffers" },
162         { offsetof (Evas_GL_API, glBindFramebuffer      ), "glBindFramebuffer" },
163         { offsetof (Evas_GL_API, glFramebufferTexture2D ), "glFramebufferTexture2D" },
164         { offsetof (Evas_GL_API, glCheckFramebufferStatus), "glCheckFramebufferStatus" },
165         { offsetof (Evas_GL_API, glDeleteFramebuffers   ), "glDeleteFramebuffers" },
166         { offsetof (Evas_GL_API, glGenRenderbuffers     ), "glGenRenderbuffers" },
167         { offsetof (Evas_GL_API, glBindRenderbuffer     ), "glBindRenderbuffer" },
168         { offsetof (Evas_GL_API, glRenderbufferStorage  ), "glRenderbufferStorage" },
169         { offsetof (Evas_GL_API, glFramebufferRenderbuffer), "glFramebufferRenderbuffer" },
170         { offsetof (Evas_GL_API, glDeleteRenderbuffers  ), "glDeleteRenderbuffers" },
171         /* multisampling functions, none supported in efl-1.12.0 */
172         { 0, NULL }
173     };
174
175     api = evas_gl_api_get (gl);
176
177     for (i = 0; evas_gl_func_map[i].name; i++) {
178         if (! strncmp (evas_gl_func_map[i].name, name, strlen(name)))
179             return *((cairo_gl_generic_func_t *) (((char *) &api->version) + evas_gl_func_map[i].func));
180     }
181
182     return evas_gl_proc_address_get (gl, name);
183 }
184
185 static cairo_bool_t
186 _context_acquisition_changed_evas_gl_state (cairo_evas_gl_context_t *ctx,
187                                             Evas_GL_Surface *current_surface)
188 {
189     return ctx->queried_context != ctx->context ||
190            ctx->current_surface != current_surface;
191 }
192
193 static Evas_GL_Surface *
194 _evas_gl_get_current_surface (cairo_evas_gl_context_t *ctx)
195 {
196     if (ctx->base.current_target == NULL ||
197         _cairo_gl_surface_is_texture (ctx->base.current_target)) {
198         return  ctx->dummy_surface;
199     }
200
201     return ((cairo_evas_gl_surface_t *) ctx->base.current_target)->surface;
202 }
203
204 static void
205 _evas_gl_query_current_state (cairo_evas_gl_context_t *ctx)
206 {
207         ctx->queried_context = evas_gl_current_context_get (ctx->evas_gl);
208         ctx->current_surface = evas_gl_current_surface_get (ctx->evas_gl);
209 }
210
211 static void
212 _evas_gl_acquire (void *abstract_ctx)
213 {
214     cairo_evas_gl_context_t *ctx = abstract_ctx;
215     Evas_GL_Surface *current_surface = _evas_gl_get_current_surface (ctx);
216
217     _evas_gl_query_current_state (ctx);
218     if (!_context_acquisition_changed_evas_gl_state (ctx, current_surface))
219         return;
220
221     _cairo_gl_context_reset (&ctx->base);
222     evas_gl_make_current (ctx->evas_gl, current_surface, ctx->context);
223
224     ctx->current_surface = current_surface;
225     //ctx->base.current_target = &ctx->dummy_surface->base;
226 }
227
228 static void
229 _evas_gl_release (void *abstract_ctx)
230 {
231     cairo_evas_gl_context_t *ctx = abstract_ctx;
232     if (!ctx->base.thread_aware || ctx->has_multithread_makecurrent ||
233         !_context_acquisition_changed_evas_gl_state (ctx,
234                                                  _evas_gl_get_current_surface (ctx))) {
235         return;
236     }
237
238     _cairo_gl_composite_flush (&ctx->base);
239     evas_gl_make_current (ctx->evas_gl, NULL, NULL);
240     ctx->current_surface = NULL;
241 }
242
243 static void
244 _evas_gl_make_current (void *abstract_ctx,
245                    cairo_gl_surface_t *abstract_surface)
246 {
247     cairo_evas_gl_context_t *ctx = abstract_ctx;
248     cairo_evas_gl_surface_t *surface = (cairo_evas_gl_surface_t *) abstract_surface;
249
250     if (surface->surface != ctx->current_surface) {
251         evas_gl_make_current (ctx->evas_gl, surface->surface, ctx->context);
252         ctx->current_surface = surface->surface;
253     }
254 }
255
256 static void
257 _evas_gl_swap_buffers (void *abstract_ctx,
258                    cairo_gl_surface_t *abstract_surface)
259 { }
260
261 static void
262 _evas_gl_destroy (void *abstract_ctx)
263 {
264     cairo_evas_gl_context_t *ctx = abstract_ctx;
265
266     evas_gl_make_current (ctx->evas_gl, NULL, NULL);
267     if (! ctx->dummy_surface)
268         evas_gl_surface_destroy (ctx->evas_gl, ctx->dummy_surface);
269 }
270
271 cairo_device_t *
272 cairo_evas_gl_device_create (Evas_GL *evas_gl,
273                              Evas_GL_Context *evas_context)
274 {
275     Evas_GL_Config *evas_cfg;
276     cairo_evas_gl_context_t *ctx;
277     cairo_status_t status;
278
279         if (! evas_gl ||! evas_context) {
280                 fprintf (stderr, "cairo_evas_gl_device_create(): evas_gl or evas_context is NULL\n");
281         return _cairo_gl_context_create_in_error (CAIRO_STATUS_NULL_POINTER);
282         }
283
284     ctx = calloc (1, sizeof (cairo_evas_gl_context_t));
285     if (unlikely (ctx == NULL))
286         return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
287
288     ctx->evas_gl = evas_gl;
289     ctx->context = evas_context;
290     evas_cfg = evas_gl_config_new ();
291
292     ctx->base.acquire = _evas_gl_acquire;
293     ctx->base.release = _evas_gl_release;
294     ctx->base.make_current = _evas_gl_make_current;
295     ctx->base.swap_buffers = _evas_gl_swap_buffers;
296     ctx->base.destroy = _evas_gl_destroy;
297
298     /* We are about the change the current state of evas-gl, so we should
299      * query the pre-existing surface now instead of later. */
300     _evas_gl_query_current_state (ctx);
301
302     ctx->dummy_surface = evas_gl_pbuffer_surface_create (ctx->evas_gl,
303                                                          evas_cfg,
304                                                          1, 1, NULL);
305     //evas_gl_config_free (evas_cfg);
306
307     if (ctx->dummy_surface == NULL) {
308         free (ctx);
309         return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
310     }
311
312     if (!evas_gl_make_current (ctx->evas_gl, ctx->dummy_surface, evas_context)) {
313         evas_gl_surface_destroy (ctx->evas_gl, ctx->dummy_surface);
314         free (ctx);
315         return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
316     }
317
318     status = _cairo_gl_dispatch_init (&ctx->base.dispatch,
319                                       _cairo_evas_gl_get_proc_addr,
320                                       ctx->evas_gl);
321     if (unlikely (status)) {
322         evas_gl_surface_destroy (ctx->evas_gl, ctx->dummy_surface);
323         free (ctx);
324         return _cairo_gl_context_create_in_error (status);
325     }
326
327     status = _cairo_gl_context_init (&ctx->base);
328     if (unlikely (status)) {
329         evas_gl_surface_destroy (ctx->evas_gl, ctx->dummy_surface);
330         free (ctx);
331         return _cairo_gl_context_create_in_error (status);
332     }
333
334     if (strstr(evas_gl_string_query (ctx->evas_gl, EVAS_GL_EXTENSIONS),
335                                      "GLX_MESA_multithread_makecurrent"))
336         ctx->has_multithread_makecurrent = TRUE;
337     else
338         ctx->has_multithread_makecurrent = FALSE;
339
340     evas_gl_make_current (ctx->evas_gl, NULL, NULL);
341     return &ctx->base.base;
342 }
343
344 cairo_surface_t *
345 cairo_gl_surface_create_for_evas_gl (cairo_device_t     *device,
346                                      Evas_GL_Surface    *evas_surface,
347                                      Evas_GL_Config     *evas_config,
348                                      int                 width,
349                                      int                 height)
350 {
351     cairo_evas_gl_surface_t *surface;
352
353         if ((! device)||(cairo_device_status(device)!= CAIRO_STATUS_SUCCESS)){
354                 fprintf (stderr, "cairo_gl_surface_create_for_evas_gl(): cairo device is NULL or not available\n");
355         return _cairo_surface_create_in_error(CAIRO_STATUS_NULL_POINTER);
356         }
357
358     if (unlikely (device->status))
359         return _cairo_surface_create_in_error (device->status);
360
361         if (! evas_surface || ! evas_config) {
362                 fprintf (stderr, "cairo_gl_surface_create_for_evas_gl(): evas_surface or evas_config is NULL\n");
363         return _cairo_surface_create_in_error (CAIRO_STATUS_NULL_POINTER);
364         }
365
366     if (device->backend->type != CAIRO_DEVICE_TYPE_GL)
367         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
368
369     if (width <= 0 || height <= 0)
370         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
371
372     surface = calloc (1, sizeof (cairo_evas_gl_surface_t));
373     if (unlikely (surface == NULL))
374         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
375
376     _cairo_gl_surface_init (device, &surface->base,
377                             CAIRO_CONTENT_COLOR_ALPHA, width, height);
378
379     if (evas_config->stencil_bits != EVAS_GL_STENCIL_NONE)
380         surface->base.supports_stencil = TRUE;
381
382     /* does not matter num of samples */
383     if (evas_config->multisample_bits != EVAS_GL_MULTISAMPLE_NONE) {
384         surface->base.num_samples = 2;
385         surface->base.supports_msaa = TRUE;
386     }
387
388     surface->base.stencil_and_msaa_caps_initialized = TRUE;
389
390     surface->surface = evas_surface;
391
392     return &surface->base.base;
393 }
394
395 static cairo_bool_t is_evas_gl_device (cairo_device_t *device)
396 {
397                 return (device->backend != NULL &&
398             device->backend->type == CAIRO_DEVICE_TYPE_GL);
399 }
400
401 static cairo_evas_gl_context_t *to_evas_gl_context (cairo_device_t *device)
402 {
403         return (cairo_evas_gl_context_t *) device;
404 }
405
406 cairo_public Evas_GL *
407 cairo_evas_gl_device_get_gl (cairo_device_t *device)
408 {
409         if ((! device)||(cairo_device_status(device)!= CAIRO_STATUS_SUCCESS)){
410                 fprintf(stderr,"\n cairo_evas_gl_device_get_gl(): cairo device is NULL or not available");
411         _cairo_error_throw(CAIRO_STATUS_DEVICE_ERROR);
412         return NULL;
413         }
414
415         if (! is_evas_gl_device (device)) {
416         _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
417         return NULL;
418     }
419
420     return to_evas_gl_context (device)->evas_gl;
421 }
422
423 cairo_public Evas_GL_Context *
424 cairo_evas_gl_device_get_context (cairo_device_t *device)
425 {
426         if ((! device)||(cairo_device_status(device)!= CAIRO_STATUS_SUCCESS)){
427                 fprintf(stderr,"\n cairo_evas_gl_device_get_context(): cairo device is NULL or not available");         
428         _cairo_error_throw (CAIRO_STATUS_DEVICE_ERROR);
429         return NULL;
430         }
431
432     if (! is_evas_gl_device (device)) {
433         _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
434         return NULL;
435     }
436
437     return to_evas_gl_context (device)->context;
438 }