1 /* cairo - a vector graphics library with display and print output
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
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.
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
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/
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.
31 * The Original Code is the cairo graphics library.
33 * The Initial Developer of the Original Code is Red Hat, Inc.
36 * Carl Worth <cworth@cworth.org>
37 * Chris Wilson <chris@chris-wilson.co.uk>
38 * Henry Song <henry.song@samsung.com>
42 #include "cairo-gl-private.h"
43 #include "cairo-error-private.h"
48 #include "cairo-evas-gl.h"
50 typedef struct _cairo_evas_gl_context {
51 cairo_gl_context_t base;
54 Evas_GL_Surface *surface;
55 Evas_GL_Context *context;
57 Evas_GL_Surface *dummy_surface;
58 Evas_GL_Surface *current_surface;
60 Evas_GL_Context *queried_context;
62 cairo_bool_t has_multithread_makecurrent;
63 } cairo_evas_gl_context_t;
65 typedef struct _cairo_evas_gl_surface {
66 cairo_gl_surface_t base;
68 Evas_GL_Surface *surface;
69 } cairo_evas_gl_surface_t;
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.
74 The following APIs are not supported by efl-1.12
75 glDrawBuffer, glReadBuffer, glMapBuffer, glUnmapBuffer,
76 glBlitFramebuffer{ANGLE}, glRenderbufferStorageMultisample{ANGLE},
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).
82 static cairo_gl_generic_func_t
83 _cairo_evas_gl_get_proc_addr (void *data, const char *name)
85 static Evas_GL_API *api;
86 Evas_GL *gl = (Evas_GL *) data;
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
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" },
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 */
175 api = evas_gl_api_get (gl);
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));
182 return evas_gl_proc_address_get (gl, name);
186 _context_acquisition_changed_evas_gl_state (cairo_evas_gl_context_t *ctx,
187 Evas_GL_Surface *current_surface)
189 return ctx->queried_context != ctx->context ||
190 ctx->current_surface != current_surface;
193 static Evas_GL_Surface *
194 _evas_gl_get_current_surface (cairo_evas_gl_context_t *ctx)
196 if (ctx->base.current_target == NULL ||
197 _cairo_gl_surface_is_texture (ctx->base.current_target)) {
198 return ctx->dummy_surface;
201 return ((cairo_evas_gl_surface_t *) ctx->base.current_target)->surface;
205 _evas_gl_query_current_state (cairo_evas_gl_context_t *ctx)
207 ctx->queried_context = evas_gl_current_context_get (ctx->evas_gl);
208 ctx->current_surface = evas_gl_current_surface_get (ctx->evas_gl);
212 _evas_gl_acquire (void *abstract_ctx)
214 cairo_evas_gl_context_t *ctx = abstract_ctx;
215 Evas_GL_Surface *current_surface = _evas_gl_get_current_surface (ctx);
217 _evas_gl_query_current_state (ctx);
218 if (!_context_acquisition_changed_evas_gl_state (ctx, current_surface))
221 _cairo_gl_context_reset (&ctx->base);
222 evas_gl_make_current (ctx->evas_gl, current_surface, ctx->context);
224 ctx->current_surface = current_surface;
225 //ctx->base.current_target = &ctx->dummy_surface->base;
229 _evas_gl_release (void *abstract_ctx)
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))) {
238 _cairo_gl_composite_flush (&ctx->base);
239 evas_gl_make_current (ctx->evas_gl, NULL, NULL);
240 ctx->current_surface = NULL;
244 _evas_gl_make_current (void *abstract_ctx,
245 cairo_gl_surface_t *abstract_surface)
247 cairo_evas_gl_context_t *ctx = abstract_ctx;
248 cairo_evas_gl_surface_t *surface = (cairo_evas_gl_surface_t *) abstract_surface;
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;
257 _evas_gl_swap_buffers (void *abstract_ctx,
258 cairo_gl_surface_t *abstract_surface)
262 _evas_gl_destroy (void *abstract_ctx)
264 cairo_evas_gl_context_t *ctx = abstract_ctx;
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);
272 cairo_evas_gl_device_create (Evas_GL *evas_gl,
273 Evas_GL_Context *evas_context)
275 Evas_GL_Config *evas_cfg;
276 cairo_evas_gl_context_t *ctx;
277 cairo_status_t status;
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);
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);
288 ctx->evas_gl = evas_gl;
289 ctx->context = evas_context;
290 evas_cfg = evas_gl_config_new ();
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;
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);
302 ctx->dummy_surface = evas_gl_pbuffer_surface_create (ctx->evas_gl,
305 //evas_gl_config_free (evas_cfg);
307 if (ctx->dummy_surface == NULL) {
309 return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
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);
315 return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
318 status = _cairo_gl_dispatch_init (&ctx->base.dispatch,
319 _cairo_evas_gl_get_proc_addr,
321 if (unlikely (status)) {
322 evas_gl_surface_destroy (ctx->evas_gl, ctx->dummy_surface);
324 return _cairo_gl_context_create_in_error (status);
327 status = _cairo_gl_context_init (&ctx->base);
328 if (unlikely (status)) {
329 evas_gl_surface_destroy (ctx->evas_gl, ctx->dummy_surface);
331 return _cairo_gl_context_create_in_error (status);
334 if (strstr(evas_gl_string_query (ctx->evas_gl, EVAS_GL_EXTENSIONS),
335 "GLX_MESA_multithread_makecurrent"))
336 ctx->has_multithread_makecurrent = TRUE;
338 ctx->has_multithread_makecurrent = FALSE;
340 evas_gl_make_current (ctx->evas_gl, NULL, NULL);
341 return &ctx->base.base;
345 cairo_gl_surface_create_for_evas_gl (cairo_device_t *device,
346 Evas_GL_Surface *evas_surface,
347 Evas_GL_Config *evas_config,
351 cairo_evas_gl_surface_t *surface;
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);
358 if (unlikely (device->status))
359 return _cairo_surface_create_in_error (device->status);
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);
366 if (device->backend->type != CAIRO_DEVICE_TYPE_GL)
367 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
369 if (width <= 0 || height <= 0)
370 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
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));
376 _cairo_gl_surface_init (device, &surface->base,
377 CAIRO_CONTENT_COLOR_ALPHA, width, height);
379 if (evas_config->stencil_bits != EVAS_GL_STENCIL_NONE)
380 surface->base.supports_stencil = TRUE;
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;
388 surface->base.stencil_and_msaa_caps_initialized = TRUE;
390 surface->surface = evas_surface;
392 return &surface->base.base;
395 static cairo_bool_t is_evas_gl_device (cairo_device_t *device)
397 return (device->backend != NULL &&
398 device->backend->type == CAIRO_DEVICE_TYPE_GL);
401 static cairo_evas_gl_context_t *to_evas_gl_context (cairo_device_t *device)
403 return (cairo_evas_gl_context_t *) device;
406 cairo_public Evas_GL *
407 cairo_evas_gl_device_get_gl (cairo_device_t *device)
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);
415 if (! is_evas_gl_device (device)) {
416 _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
420 return to_evas_gl_context (device)->evas_gl;
423 cairo_public Evas_GL_Context *
424 cairo_evas_gl_device_get_context (cairo_device_t *device)
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);
432 if (! is_evas_gl_device (device)) {
433 _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
437 return to_evas_gl_context (device)->context;