Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3959 Serge 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
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it either under the terms of the GNU Lesser General Public
9
 * License version 2.1 as published by the Free Software Foundation
10
 * (the "LGPL") or, at your option, under the terms of the Mozilla
11
 * Public License Version 1.1 (the "MPL"). If you do not alter this
12
 * notice, a recipient may use your version of this file under either
13
 * the MPL or the LGPL.
14
 *
15
 * You should have received a copy of the LGPL along with this library
16
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18
 * You should have received a copy of the MPL along with this library
19
 * in the file COPYING-MPL-1.1
20
 *
21
 * The contents of this file are subject to the Mozilla Public License
22
 * Version 1.1 (the "License"); you may not use this file except in
23
 * compliance with the License. You may obtain a copy of the License at
24
 * http://www.mozilla.org/MPL/
25
 *
26
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28
 * the specific language governing rights and limitations.
29
 *
30
 * The Original Code is the cairo graphics library.
31
 *
32
 * The Initial Developer of the Original Code is Red Hat, Inc.
33
 *
34
 * Contributor(s):
35
 *	Carl Worth 
36
 *	Chris Wilson 
37
 */
38
 
39
#include "cairoint.h"
40
 
41
#include "cairo-gl-private.h"
42
 
43
#include "cairo-error-private.h"
44
 
45
typedef struct _cairo_egl_context {
46
    cairo_gl_context_t base;
47
 
48
    EGLDisplay display;
49
    EGLContext context;
50
 
51
    EGLSurface dummy_surface;
52
 
53
    EGLContext previous_context;
54
    EGLSurface previous_surface;
55
} cairo_egl_context_t;
56
 
57
typedef struct _cairo_egl_surface {
58
    cairo_gl_surface_t base;
59
 
60
    EGLSurface egl;
61
} cairo_egl_surface_t;
62
 
63
 
64
static cairo_bool_t
65
_context_acquisition_changed_egl_state (cairo_egl_context_t *ctx,
66
					EGLSurface current_surface)
67
{
68
    return ctx->previous_context != ctx->context ||
69
	   ctx->previous_surface != current_surface;
70
}
71
 
72
static EGLSurface
73
_egl_get_current_surface (cairo_egl_context_t *ctx)
74
{
75
    if (ctx->base.current_target == NULL ||
76
        _cairo_gl_surface_is_texture (ctx->base.current_target)) {
77
	return  ctx->dummy_surface;
78
    }
79
 
80
    return ((cairo_egl_surface_t *) ctx->base.current_target)->egl;
81
}
82
 
83
static void
84
_egl_query_current_state (cairo_egl_context_t *ctx)
85
{
86
    ctx->previous_surface = eglGetCurrentSurface (EGL_DRAW);
87
    ctx->previous_context = eglGetCurrentContext ();
88
 
89
    /* If any of the values were none, assume they are all none. Not all
90
       drivers seem well behaved when it comes to using these values across
91
       multiple threads. */
92
    if (ctx->previous_surface == EGL_NO_SURFACE ||
93
	ctx->previous_context == EGL_NO_CONTEXT) {
94
	ctx->previous_surface = EGL_NO_SURFACE;
95
	ctx->previous_context = EGL_NO_CONTEXT;
96
    }
97
}
98
 
99
static void
100
_egl_acquire (void *abstract_ctx)
101
{
102
    cairo_egl_context_t *ctx = abstract_ctx;
103
    EGLSurface current_surface = _egl_get_current_surface (ctx);
104
 
105
    _egl_query_current_state (ctx);
106
    if (!_context_acquisition_changed_egl_state (ctx, current_surface))
107
	return;
108
 
109
    eglMakeCurrent (ctx->display,
110
		    current_surface, current_surface, ctx->context);
111
}
112
 
113
static void
114
_egl_release (void *abstract_ctx)
115
{
116
    cairo_egl_context_t *ctx = abstract_ctx;
117
    if (!ctx->base.thread_aware ||
118
	!_context_acquisition_changed_egl_state (ctx,
119
						 _egl_get_current_surface (ctx))) {
120
	return;
121
    }
122
 
123
    eglMakeCurrent (ctx->display,
124
		    EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
125
}
126
 
127
static void
128
_egl_make_current (void *abstract_ctx,
129
	           cairo_gl_surface_t *abstract_surface)
130
{
131
    cairo_egl_context_t *ctx = abstract_ctx;
132
    cairo_egl_surface_t *surface = (cairo_egl_surface_t *) abstract_surface;
133
 
134
    eglMakeCurrent(ctx->display, surface->egl, surface->egl, ctx->context);
135
}
136
 
137
static void
138
_egl_swap_buffers (void *abstract_ctx,
139
		   cairo_gl_surface_t *abstract_surface)
140
{
141
    cairo_egl_context_t *ctx = abstract_ctx;
142
    cairo_egl_surface_t *surface = (cairo_egl_surface_t *) abstract_surface;
143
 
144
    eglSwapBuffers (ctx->display, surface->egl);
145
}
146
 
147
static void
148
_egl_destroy (void *abstract_ctx)
149
{
150
    cairo_egl_context_t *ctx = abstract_ctx;
151
 
152
    eglMakeCurrent (ctx->display,
153
		    EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
154
    if (ctx->dummy_surface != EGL_NO_SURFACE)
155
        eglDestroySurface (ctx->display, ctx->dummy_surface);
156
}
157
 
158
static cairo_bool_t
159
_egl_make_current_surfaceless(cairo_egl_context_t *ctx)
160
{
161
    const char *extensions;
162
 
163
    extensions = eglQueryString(ctx->display, EGL_EXTENSIONS);
164
    if (strstr(extensions, "EGL_KHR_surfaceless_context") == NULL &&
165
	strstr(extensions, "EGL_KHR_surfaceless_opengl") == NULL)
166
	return FALSE;
167
 
168
    if (!eglMakeCurrent(ctx->display,
169
			EGL_NO_SURFACE, EGL_NO_SURFACE, ctx->context))
170
	return FALSE;
171
 
172
    return TRUE;
173
}
174
 
175
cairo_device_t *
176
cairo_egl_device_create (EGLDisplay dpy, EGLContext egl)
177
{
178
    cairo_egl_context_t *ctx;
179
    cairo_status_t status;
180
    int attribs[] = {
181
	EGL_WIDTH, 1,
182
	EGL_HEIGHT, 1,
183
	EGL_NONE,
184
    };
185
    EGLConfig config;
186
    EGLint numConfigs;
187
 
188
    ctx = calloc (1, sizeof (cairo_egl_context_t));
189
    if (unlikely (ctx == NULL))
190
	return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
191
 
192
    ctx->display = dpy;
193
    ctx->context = egl;
194
 
195
    ctx->base.acquire = _egl_acquire;
196
    ctx->base.release = _egl_release;
197
    ctx->base.make_current = _egl_make_current;
198
    ctx->base.swap_buffers = _egl_swap_buffers;
199
    ctx->base.destroy = _egl_destroy;
200
 
201
    /* We are about the change the current state of EGL, so we should
202
     * query the pre-existing surface now instead of later. */
203
    _egl_query_current_state (ctx);
204
 
205
    if (!_egl_make_current_surfaceless (ctx)) {
206
	/* Fall back to dummy surface, meh. */
207
	EGLint config_attribs[] = {
208
	    EGL_CONFIG_ID, 0,
209
	    EGL_NONE
210
	};
211
 
212
	/*
213
	 * In order to be able to make an egl context current when using a
214
	 * pbuffer surface, that surface must have been created with a config
215
	 * that is compatible with the context config. For Mesa, this means
216
	 * that the configs must be the same.
217
	 */
218
	eglQueryContext (dpy, egl, EGL_CONFIG_ID, &config_attribs[1]);
219
	eglChooseConfig (dpy, config_attribs, &config, 1, &numConfigs);
220
 
221
	ctx->dummy_surface = eglCreatePbufferSurface (dpy, config, attribs);
222
	if (ctx->dummy_surface == NULL) {
223
	    free (ctx);
224
	    return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
225
	}
226
 
227
	if (!eglMakeCurrent (dpy, ctx->dummy_surface, ctx->dummy_surface, egl)) {
228
	    free (ctx);
229
	    return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
230
	}
231
    }
232
 
233
    status = _cairo_gl_dispatch_init (&ctx->base.dispatch, eglGetProcAddress);
234
    if (unlikely (status)) {
235
	free (ctx);
236
	return _cairo_gl_context_create_in_error (status);
237
    }
238
 
239
    status = _cairo_gl_context_init (&ctx->base);
240
    if (unlikely (status)) {
241
	if (ctx->dummy_surface != EGL_NO_SURFACE)
242
	    eglDestroySurface (dpy, ctx->dummy_surface);
243
	free (ctx);
244
	return _cairo_gl_context_create_in_error (status);
245
    }
246
 
247
    eglMakeCurrent (dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
248
 
249
    return &ctx->base.base;
250
}
251
 
252
cairo_surface_t *
253
cairo_gl_surface_create_for_egl (cairo_device_t	*device,
254
				 EGLSurface	 egl,
255
				 int		 width,
256
				 int		 height)
257
{
258
    cairo_egl_surface_t *surface;
259
 
260
    if (unlikely (device->status))
261
	return _cairo_surface_create_in_error (device->status);
262
 
263
    if (device->backend->type != CAIRO_DEVICE_TYPE_GL)
264
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
265
 
266
    if (width <= 0 || height <= 0)
267
        return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
268
 
269
    surface = calloc (1, sizeof (cairo_egl_surface_t));
270
    if (unlikely (surface == NULL))
271
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
272
 
273
    _cairo_gl_surface_init (device, &surface->base,
274
			    CAIRO_CONTENT_COLOR_ALPHA, width, height);
275
    surface->egl = egl;
276
 
277
    return &surface->base.base;
278
}
279
 
280
static cairo_bool_t is_egl_device (cairo_device_t *device)
281
{
282
    return (device->backend != NULL &&
283
	    device->backend->type == CAIRO_DEVICE_TYPE_GL);
284
}
285
 
286
static cairo_egl_context_t *to_egl_context (cairo_device_t *device)
287
{
288
    return (cairo_egl_context_t *) device;
289
}
290
 
291
EGLDisplay
292
cairo_egl_device_get_display (cairo_device_t *device)
293
{
294
    if (! is_egl_device (device)) {
295
	_cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
296
	return EGL_NO_DISPLAY;
297
    }
298
 
299
    return to_egl_context (device)->display;
300
}
301
 
302
cairo_public EGLContext
303
cairo_egl_device_get_context (cairo_device_t *device)
304
{
305
    if (! is_egl_device (device)) {
306
	_cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
307
	return EGL_NO_CONTEXT;
308
    }
309
 
310
    return to_egl_context (device)->context;
311
}