1df57d0777490ccc63cd5cf659e44e23f18e9a11
[mesa.git] / src / gallium / state_trackers / egl / common / egl_g3d_st.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.9
4 *
5 * Copyright (C) 2010 LunarG Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 * Authors:
26 * Chia-I Wu <olv@lunarg.com>
27 */
28
29 #include "util/u_memory.h"
30 #include "util/u_string.h"
31 #include "util/u_inlines.h"
32 #include "util/u_dl.h"
33 #include "egldriver.h"
34 #include "eglimage.h"
35 #include "eglmutex.h"
36
37 #include "egl_g3d.h"
38 #include "egl_g3d_st.h"
39
40 struct egl_g3d_st_manager {
41 struct st_manager base;
42 _EGLDisplay *display;
43 };
44
45 static INLINE struct egl_g3d_st_manager *
46 egl_g3d_st_manager(struct st_manager *smapi)
47 {
48 return (struct egl_g3d_st_manager *) smapi;
49 }
50
51 static struct egl_g3d_st_module {
52 const char *filename;
53 struct util_dl_library *lib;
54 struct st_api *stapi;
55 } egl_g3d_st_modules[ST_API_COUNT];
56
57 static EGLBoolean
58 egl_g3d_search_path_callback(const char *dir, size_t len, void *callback_data)
59 {
60 struct egl_g3d_st_module *stmod =
61 (struct egl_g3d_st_module *) callback_data;
62 char path[1024];
63 int ret;
64
65 ret = util_snprintf(path, sizeof(path),
66 "%.*s/%s", len, dir, stmod->filename);
67 if (ret > 0 && ret < sizeof(path))
68 stmod->lib = util_dl_open(path);
69
70 return !(stmod->lib);
71 }
72
73 static boolean
74 egl_g3d_load_st_module(struct egl_g3d_st_module *stmod,
75 const char *filename, const char *procname)
76 {
77 struct st_api *(*create_api)(void);
78
79 stmod->filename = filename;
80 if (stmod->filename)
81 _eglSearchPathForEach(egl_g3d_search_path_callback, (void *) stmod);
82 else
83 stmod->lib = util_dl_open(NULL);
84
85 if (stmod->lib) {
86 create_api = (struct st_api *(*)(void))
87 util_dl_get_proc_address(stmod->lib, procname);
88 if (create_api)
89 stmod->stapi = create_api();
90
91 if (!stmod->stapi) {
92 util_dl_close(stmod->lib);
93 stmod->lib = NULL;
94 }
95 }
96
97 if (stmod->stapi) {
98 return TRUE;
99 }
100 else {
101 stmod->filename = NULL;
102 return FALSE;
103 }
104 }
105
106 void
107 egl_g3d_init_st_apis(struct st_api *stapis[ST_API_COUNT])
108 {
109 const char *skip_checks[ST_API_COUNT], *symbols[ST_API_COUNT];
110 const char *filenames[ST_API_COUNT][4];
111 struct util_dl_library *self;
112 int num_needed = 0, api;
113
114 self = util_dl_open(NULL);
115
116 /* collect the necessary data for loading modules */
117 for (api = 0; api < ST_API_COUNT; api++) {
118 int count = 0;
119
120 switch (api) {
121 case ST_API_OPENGL:
122 skip_checks[api] = "glColor4d";
123 symbols[api] = ST_CREATE_OPENGL_SYMBOL;
124 filenames[api][count++] = "api_GL.so";
125 break;
126 case ST_API_OPENGL_ES1:
127 skip_checks[api] = "glColor4x";
128 symbols[api] = ST_CREATE_OPENGL_ES1_SYMBOL;
129 filenames[api][count++] = "api_GLESv1_CM.so";
130 filenames[api][count++] = "api_GL.so";
131 break;
132 case ST_API_OPENGL_ES2:
133 skip_checks[api] = "glShaderBinary";
134 symbols[api] = ST_CREATE_OPENGL_ES2_SYMBOL;
135 filenames[api][count++] = "api_GLESv2.so";
136 filenames[api][count++] = "api_GL.so";
137 break;
138 case ST_API_OPENVG:
139 skip_checks[api] = "vgClear";
140 symbols[api] = ST_CREATE_OPENVG_SYMBOL;
141 filenames[api][count++]= "api_OpenVG.so";
142 break;
143 default:
144 assert(!"Unknown API Type\n");
145 skip_checks[api] = NULL;
146 symbols[api] = NULL;
147 break;
148 }
149 filenames[api][count++]= NULL;
150 assert(count < Elements(filenames[api]));
151
152 /* heuristicically decide if the module is needed */
153 if (!self || !skip_checks[api] ||
154 util_dl_get_proc_address(self, skip_checks[api])) {
155 /* unset so the module is not skipped */
156 skip_checks[api] = NULL;
157 num_needed++;
158 }
159 }
160 /* mark all moudles needed if we wrongly decided that none is needed */
161 if (!num_needed)
162 memset(skip_checks, 0, sizeof(skip_checks));
163
164 if (self)
165 util_dl_close(self);
166
167 for (api = 0; api < ST_API_COUNT; api++) {
168 struct egl_g3d_st_module *stmod = &egl_g3d_st_modules[api];
169 const char **p;
170
171 /* skip the module */
172 if (skip_checks[api])
173 continue;
174
175 /* try all filenames, including NULL */
176 for (p = filenames[api]; *p; p++) {
177 if (egl_g3d_load_st_module(stmod, *p, symbols[api]))
178 break;
179 }
180 if (!stmod->stapi)
181 egl_g3d_load_st_module(stmod, NULL, symbols[api]);
182
183 stapis[api] = stmod->stapi;
184 }
185 }
186
187 void
188 egl_g3d_destroy_st_apis(void)
189 {
190 int api;
191
192 for (api = 0; api < ST_API_COUNT; api++) {
193 struct egl_g3d_st_module *stmod = &egl_g3d_st_modules[api];
194
195 if (stmod->stapi) {
196 stmod->stapi->destroy(stmod->stapi);
197 stmod->stapi = NULL;
198 }
199 if (stmod->lib) {
200 util_dl_close(stmod->lib);
201 stmod->lib = NULL;
202 }
203 stmod->filename = NULL;
204 }
205 }
206
207 static boolean
208 egl_g3d_st_manager_get_egl_image(struct st_manager *smapi,
209 struct st_egl_image *stimg)
210 {
211 struct egl_g3d_st_manager *gsmapi = egl_g3d_st_manager(smapi);
212 EGLImageKHR handle = (EGLImageKHR) stimg->egl_image;
213 _EGLImage *img;
214 struct egl_g3d_image *gimg;
215
216 /* this is called from state trackers */
217 _eglLockMutex(&gsmapi->display->Mutex);
218
219 img = _eglLookupImage(handle, gsmapi->display);
220 if (!img) {
221 _eglUnlockMutex(&gsmapi->display->Mutex);
222 return FALSE;
223 }
224
225 gimg = egl_g3d_image(img);
226
227 stimg->texture = NULL;
228 pipe_resource_reference(&stimg->texture, gimg->texture);
229 stimg->face = gimg->face;
230 stimg->level = gimg->level;
231 stimg->zslice = gimg->zslice;
232
233 _eglUnlockMutex(&gsmapi->display->Mutex);
234
235 return TRUE;
236 }
237
238 struct st_manager *
239 egl_g3d_create_st_manager(_EGLDisplay *dpy)
240 {
241 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
242 struct egl_g3d_st_manager *gsmapi;
243
244 gsmapi = CALLOC_STRUCT(egl_g3d_st_manager);
245 if (gsmapi) {
246 gsmapi->display = dpy;
247
248 gsmapi->base.screen = gdpy->native->screen;
249 gsmapi->base.get_egl_image = egl_g3d_st_manager_get_egl_image;
250 }
251
252 return &gsmapi->base;;
253 }
254
255 void
256 egl_g3d_destroy_st_manager(struct st_manager *smapi)
257 {
258 struct egl_g3d_st_manager *gsmapi = egl_g3d_st_manager(smapi);
259 FREE(gsmapi);
260 }
261
262 static boolean
263 egl_g3d_st_framebuffer_flush_front_pbuffer(struct st_framebuffer_iface *stfbi,
264 enum st_attachment_type statt)
265 {
266 return TRUE;
267 }
268
269 static boolean
270 egl_g3d_st_framebuffer_validate_pbuffer(struct st_framebuffer_iface *stfbi,
271 const enum st_attachment_type *statts,
272 unsigned count,
273 struct pipe_resource **out)
274 {
275 _EGLSurface *surf = (_EGLSurface *) stfbi->st_manager_private;
276 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
277 struct pipe_resource templ;
278 unsigned i;
279
280 for (i = 0; i < count; i++) {
281 out[i] = NULL;
282
283 if (gsurf->stvis.render_buffer != statts[i])
284 continue;
285
286 if (!gsurf->render_texture) {
287 struct egl_g3d_display *gdpy =
288 egl_g3d_display(gsurf->base.Resource.Display);
289 struct pipe_screen *screen = gdpy->native->screen;
290
291 memset(&templ, 0, sizeof(templ));
292 templ.target = PIPE_TEXTURE_2D;
293 templ.last_level = 0;
294 templ.width0 = gsurf->base.Width;
295 templ.height0 = gsurf->base.Height;
296 templ.depth0 = 1;
297 templ.format = gsurf->stvis.color_format;
298 templ.bind = PIPE_BIND_RENDER_TARGET;
299
300 gsurf->render_texture = screen->resource_create(screen, &templ);
301 }
302
303 pipe_resource_reference(&out[i], gsurf->render_texture);
304 }
305
306 return TRUE;
307 }
308
309 static boolean
310 egl_g3d_st_framebuffer_flush_front(struct st_framebuffer_iface *stfbi,
311 enum st_attachment_type statt)
312 {
313 _EGLSurface *surf = (_EGLSurface *) stfbi->st_manager_private;
314 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
315
316 return gsurf->native->flush_frontbuffer(gsurf->native);
317 }
318
319 static boolean
320 egl_g3d_st_framebuffer_validate(struct st_framebuffer_iface *stfbi,
321 const enum st_attachment_type *statts,
322 unsigned count,
323 struct pipe_resource **out)
324 {
325 _EGLSurface *surf = (_EGLSurface *) stfbi->st_manager_private;
326 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
327 struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS];
328 uint attachment_mask = 0;
329 unsigned i;
330
331 for (i = 0; i < count; i++) {
332 int natt;
333
334 switch (statts[i]) {
335 case ST_ATTACHMENT_FRONT_LEFT:
336 natt = NATIVE_ATTACHMENT_FRONT_LEFT;
337 break;
338 case ST_ATTACHMENT_BACK_LEFT:
339 natt = NATIVE_ATTACHMENT_BACK_LEFT;
340 break;
341 case ST_ATTACHMENT_FRONT_RIGHT:
342 natt = NATIVE_ATTACHMENT_FRONT_RIGHT;
343 break;
344 case ST_ATTACHMENT_BACK_RIGHT:
345 natt = NATIVE_ATTACHMENT_BACK_RIGHT;
346 break;
347 default:
348 natt = -1;
349 break;
350 }
351
352 if (natt >= 0)
353 attachment_mask |= 1 << natt;
354 }
355
356 if (!gsurf->native->validate(gsurf->native, attachment_mask,
357 &gsurf->sequence_number, textures, &gsurf->base.Width,
358 &gsurf->base.Height))
359 return FALSE;
360
361 for (i = 0; i < count; i++) {
362 struct pipe_resource *tex;
363 int natt;
364
365 switch (statts[i]) {
366 case ST_ATTACHMENT_FRONT_LEFT:
367 natt = NATIVE_ATTACHMENT_FRONT_LEFT;
368 break;
369 case ST_ATTACHMENT_BACK_LEFT:
370 natt = NATIVE_ATTACHMENT_BACK_LEFT;
371 break;
372 case ST_ATTACHMENT_FRONT_RIGHT:
373 natt = NATIVE_ATTACHMENT_FRONT_RIGHT;
374 break;
375 case ST_ATTACHMENT_BACK_RIGHT:
376 natt = NATIVE_ATTACHMENT_BACK_RIGHT;
377 break;
378 default:
379 natt = -1;
380 break;
381 }
382
383 if (natt >= 0) {
384 tex = textures[natt];
385
386 if (statts[i] == stfbi->visual->render_buffer)
387 pipe_resource_reference(&gsurf->render_texture, tex);
388
389 if (attachment_mask & (1 << natt)) {
390 /* transfer the ownership to the caller */
391 out[i] = tex;
392 attachment_mask &= ~(1 << natt);
393 }
394 else {
395 /* the attachment is listed more than once */
396 pipe_resource_reference(&out[i], tex);
397 }
398 }
399 }
400
401 return TRUE;
402 }
403
404 struct st_framebuffer_iface *
405 egl_g3d_create_st_framebuffer(_EGLSurface *surf)
406 {
407 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
408 struct st_framebuffer_iface *stfbi;
409
410 stfbi = CALLOC_STRUCT(st_framebuffer_iface);
411 if (!stfbi)
412 return NULL;
413
414 stfbi->visual = &gsurf->stvis;
415 if (gsurf->base.Type != EGL_PBUFFER_BIT) {
416 stfbi->flush_front = egl_g3d_st_framebuffer_flush_front;
417 stfbi->validate = egl_g3d_st_framebuffer_validate;
418 }
419 else {
420 stfbi->flush_front = egl_g3d_st_framebuffer_flush_front_pbuffer;
421 stfbi->validate = egl_g3d_st_framebuffer_validate_pbuffer;
422 }
423 stfbi->st_manager_private = (void *) &gsurf->base;
424
425 return stfbi;
426 }
427
428 void
429 egl_g3d_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi)
430 {
431 FREE(stfbi);
432 }