Merge branch 'gallium-newclear'
[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_pointer.h"
33 #include "util/u_format.h"
34 #include "util/u_dl.h"
35 #include "egldriver.h"
36 #include "eglimage.h"
37 #include "eglmutex.h"
38
39 #include "egl_g3d.h"
40 #include "egl_g3d_st.h"
41
42 struct egl_g3d_st_manager {
43 struct st_manager base;
44 _EGLDisplay *display;
45 };
46
47 static INLINE struct egl_g3d_st_manager *
48 egl_g3d_st_manager(struct st_manager *smapi)
49 {
50 return (struct egl_g3d_st_manager *) smapi;
51 }
52
53 static struct egl_g3d_st_module {
54 const char *filename;
55 struct util_dl_library *lib;
56 struct st_api *stapi;
57 } egl_g3d_st_modules[ST_API_COUNT];
58
59 static EGLBoolean
60 egl_g3d_search_path_callback(const char *dir, size_t len, void *callback_data)
61 {
62 struct egl_g3d_st_module *stmod =
63 (struct egl_g3d_st_module *) callback_data;
64 char path[1024];
65 int ret;
66
67 if (!len) {
68 stmod->lib = util_dl_open(stmod->filename);
69 return !(stmod->lib);
70 }
71
72 ret = util_snprintf(path, sizeof(path),
73 "%.*s/%s", len, dir, stmod->filename);
74 if (ret > 0 && ret < sizeof(path))
75 stmod->lib = util_dl_open(path);
76
77 return !(stmod->lib);
78 }
79
80 static boolean
81 egl_g3d_load_st_module(struct egl_g3d_st_module *stmod,
82 const char *filename, const char *procname)
83 {
84 struct st_api *(*create_api)(void);
85
86 stmod->filename = filename;
87 if (stmod->filename)
88 _eglSearchPathForEach(egl_g3d_search_path_callback, (void *) stmod);
89 else
90 stmod->lib = util_dl_open(NULL);
91
92 if (stmod->lib) {
93 create_api = (struct st_api *(*)(void))
94 util_dl_get_proc_address(stmod->lib, procname);
95 if (create_api)
96 stmod->stapi = create_api();
97
98 if (!stmod->stapi) {
99 util_dl_close(stmod->lib);
100 stmod->lib = NULL;
101 }
102 }
103
104 if (stmod->stapi) {
105 return TRUE;
106 }
107 else {
108 stmod->filename = NULL;
109 return FALSE;
110 }
111 }
112
113 #ifdef PIPE_OS_WINDOWS
114 #define ST_MODULE_SUFFIX ".dll"
115 #else
116 #define ST_MODULE_SUFFIX ".so"
117 #endif
118
119 void
120 egl_g3d_init_st_apis(struct st_api *stapis[ST_API_COUNT])
121 {
122 const char *skip_checks[ST_API_COUNT], *symbols[ST_API_COUNT];
123 const char *filenames[ST_API_COUNT][4];
124 struct util_dl_library *self;
125 int num_needed = 0, api;
126
127 self = util_dl_open(NULL);
128
129 /* collect the necessary data for loading modules */
130 for (api = 0; api < ST_API_COUNT; api++) {
131 int count = 0;
132
133 switch (api) {
134 case ST_API_OPENGL:
135 skip_checks[api] = "glColor4d";
136 symbols[api] = ST_CREATE_OPENGL_SYMBOL;
137 filenames[api][count++] = "api_GL" ST_MODULE_SUFFIX;
138 break;
139 case ST_API_OPENGL_ES1:
140 skip_checks[api] = "glColor4x";
141 symbols[api] = ST_CREATE_OPENGL_ES1_SYMBOL;
142 filenames[api][count++] = "api_GLESv1_CM" ST_MODULE_SUFFIX;
143 filenames[api][count++] = "api_GL" ST_MODULE_SUFFIX;
144 break;
145 case ST_API_OPENGL_ES2:
146 skip_checks[api] = "glShaderBinary";
147 symbols[api] = ST_CREATE_OPENGL_ES2_SYMBOL;
148 filenames[api][count++] = "api_GLESv2" ST_MODULE_SUFFIX;
149 filenames[api][count++] = "api_GL" ST_MODULE_SUFFIX;
150 break;
151 case ST_API_OPENVG:
152 skip_checks[api] = "vgClear";
153 symbols[api] = ST_CREATE_OPENVG_SYMBOL;
154 filenames[api][count++]= "api_OpenVG" ST_MODULE_SUFFIX;
155 break;
156 default:
157 assert(!"Unknown API Type\n");
158 skip_checks[api] = NULL;
159 symbols[api] = NULL;
160 break;
161 }
162 filenames[api][count++]= NULL;
163 assert(count < Elements(filenames[api]));
164
165 /* heuristicically decide if the module is needed */
166 if (!self || !skip_checks[api] ||
167 util_dl_get_proc_address(self, skip_checks[api])) {
168 /* unset so the module is not skipped */
169 skip_checks[api] = NULL;
170 num_needed++;
171 }
172 }
173 /* mark all moudles needed if we wrongly decided that none is needed */
174 if (!num_needed)
175 memset(skip_checks, 0, sizeof(skip_checks));
176
177 if (self)
178 util_dl_close(self);
179
180 for (api = 0; api < ST_API_COUNT; api++) {
181 struct egl_g3d_st_module *stmod = &egl_g3d_st_modules[api];
182 const char **p;
183
184 /* skip the module */
185 if (skip_checks[api])
186 continue;
187
188 /* try all filenames, including NULL */
189 for (p = filenames[api]; *p; p++) {
190 if (egl_g3d_load_st_module(stmod, *p, symbols[api]))
191 break;
192 }
193 if (!stmod->stapi)
194 egl_g3d_load_st_module(stmod, NULL, symbols[api]);
195
196 stapis[api] = stmod->stapi;
197 }
198 }
199
200 void
201 egl_g3d_destroy_st_apis(void)
202 {
203 int api;
204
205 for (api = 0; api < ST_API_COUNT; api++) {
206 struct egl_g3d_st_module *stmod = &egl_g3d_st_modules[api];
207
208 if (stmod->stapi) {
209 stmod->stapi->destroy(stmod->stapi);
210 stmod->stapi = NULL;
211 }
212 if (stmod->lib) {
213 util_dl_close(stmod->lib);
214 stmod->lib = NULL;
215 }
216 stmod->filename = NULL;
217 }
218 }
219
220 static boolean
221 egl_g3d_st_manager_get_egl_image(struct st_manager *smapi,
222 struct st_context_iface *stctx,
223 void *egl_image,
224 struct st_egl_image *out)
225 {
226 struct egl_g3d_st_manager *gsmapi = egl_g3d_st_manager(smapi);
227 EGLImageKHR handle = (EGLImageKHR) egl_image;
228 _EGLImage *img;
229 struct egl_g3d_image *gimg;
230
231 /* this is called from state trackers */
232 _eglLockMutex(&gsmapi->display->Mutex);
233
234 img = _eglLookupImage(handle, gsmapi->display);
235 if (!img) {
236 _eglUnlockMutex(&gsmapi->display->Mutex);
237 return FALSE;
238 }
239
240 gimg = egl_g3d_image(img);
241
242 out->texture = NULL;
243 pipe_resource_reference(&out->texture, gimg->texture);
244 out->face = gimg->face;
245 out->level = gimg->level;
246 out->zslice = gimg->zslice;
247
248 _eglUnlockMutex(&gsmapi->display->Mutex);
249
250 return TRUE;
251 }
252
253 static int
254 egl_g3d_st_manager_get_param(struct st_manager *smapi,
255 enum st_manager_param param)
256 {
257 return 0;
258 }
259
260 struct st_manager *
261 egl_g3d_create_st_manager(_EGLDisplay *dpy)
262 {
263 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
264 struct egl_g3d_st_manager *gsmapi;
265
266 gsmapi = CALLOC_STRUCT(egl_g3d_st_manager);
267 if (gsmapi) {
268 gsmapi->display = dpy;
269
270 gsmapi->base.screen = gdpy->native->screen;
271 gsmapi->base.get_egl_image = egl_g3d_st_manager_get_egl_image;
272 gsmapi->base.get_param = egl_g3d_st_manager_get_param;
273 }
274
275 return &gsmapi->base;;
276 }
277
278 void
279 egl_g3d_destroy_st_manager(struct st_manager *smapi)
280 {
281 struct egl_g3d_st_manager *gsmapi = egl_g3d_st_manager(smapi);
282 FREE(gsmapi);
283 }
284
285 static boolean
286 egl_g3d_st_framebuffer_flush_front_pbuffer(struct st_framebuffer_iface *stfbi,
287 enum st_attachment_type statt)
288 {
289 return TRUE;
290 }
291
292 static void
293 pbuffer_reference_openvg_image(struct egl_g3d_surface *gsurf)
294 {
295 /* TODO */
296 }
297
298 static void
299 pbuffer_allocate_render_texture(struct egl_g3d_surface *gsurf)
300 {
301 struct egl_g3d_display *gdpy =
302 egl_g3d_display(gsurf->base.Resource.Display);
303 struct pipe_screen *screen = gdpy->native->screen;
304 struct pipe_resource templ, *ptex;
305
306 memset(&templ, 0, sizeof(templ));
307 templ.target = PIPE_TEXTURE_2D;
308 templ.last_level = 0;
309 templ.width0 = gsurf->base.Width;
310 templ.height0 = gsurf->base.Height;
311 templ.depth0 = 1;
312 templ.format = gsurf->stvis.color_format;
313 templ.bind = PIPE_BIND_RENDER_TARGET;
314
315 ptex = screen->resource_create(screen, &templ);
316 gsurf->render_texture = ptex;
317 }
318
319 static boolean
320 egl_g3d_st_framebuffer_validate_pbuffer(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 unsigned i;
328
329 for (i = 0; i < count; i++) {
330 out[i] = NULL;
331
332 if (gsurf->stvis.render_buffer != statts[i])
333 continue;
334
335 if (!gsurf->render_texture) {
336 switch (gsurf->client_buffer_type) {
337 case EGL_NONE:
338 pbuffer_allocate_render_texture(gsurf);
339 break;
340 case EGL_OPENVG_IMAGE:
341 pbuffer_reference_openvg_image(gsurf);
342 break;
343 default:
344 break;
345 }
346
347 if (!gsurf->render_texture)
348 return FALSE;
349 }
350
351 pipe_resource_reference(&out[i], gsurf->render_texture);
352 }
353
354 return TRUE;
355 }
356
357 static boolean
358 egl_g3d_st_framebuffer_flush_front(struct st_framebuffer_iface *stfbi,
359 enum st_attachment_type statt)
360 {
361 _EGLSurface *surf = (_EGLSurface *) stfbi->st_manager_private;
362 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
363
364 return gsurf->native->flush_frontbuffer(gsurf->native);
365 }
366
367 static boolean
368 egl_g3d_st_framebuffer_validate(struct st_framebuffer_iface *stfbi,
369 const enum st_attachment_type *statts,
370 unsigned count,
371 struct pipe_resource **out)
372 {
373 _EGLSurface *surf = (_EGLSurface *) stfbi->st_manager_private;
374 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
375 struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS];
376 uint attachment_mask = 0;
377 unsigned i;
378
379 for (i = 0; i < count; i++) {
380 int natt;
381
382 switch (statts[i]) {
383 case ST_ATTACHMENT_FRONT_LEFT:
384 natt = NATIVE_ATTACHMENT_FRONT_LEFT;
385 break;
386 case ST_ATTACHMENT_BACK_LEFT:
387 natt = NATIVE_ATTACHMENT_BACK_LEFT;
388 break;
389 case ST_ATTACHMENT_FRONT_RIGHT:
390 natt = NATIVE_ATTACHMENT_FRONT_RIGHT;
391 break;
392 case ST_ATTACHMENT_BACK_RIGHT:
393 natt = NATIVE_ATTACHMENT_BACK_RIGHT;
394 break;
395 default:
396 natt = -1;
397 break;
398 }
399
400 if (natt >= 0)
401 attachment_mask |= 1 << natt;
402 }
403
404 if (!gsurf->native->validate(gsurf->native, attachment_mask,
405 &gsurf->sequence_number, textures, &gsurf->base.Width,
406 &gsurf->base.Height))
407 return FALSE;
408
409 for (i = 0; i < count; i++) {
410 struct pipe_resource *tex;
411 int natt;
412
413 switch (statts[i]) {
414 case ST_ATTACHMENT_FRONT_LEFT:
415 natt = NATIVE_ATTACHMENT_FRONT_LEFT;
416 break;
417 case ST_ATTACHMENT_BACK_LEFT:
418 natt = NATIVE_ATTACHMENT_BACK_LEFT;
419 break;
420 case ST_ATTACHMENT_FRONT_RIGHT:
421 natt = NATIVE_ATTACHMENT_FRONT_RIGHT;
422 break;
423 case ST_ATTACHMENT_BACK_RIGHT:
424 natt = NATIVE_ATTACHMENT_BACK_RIGHT;
425 break;
426 default:
427 natt = -1;
428 break;
429 }
430
431 if (natt >= 0) {
432 tex = textures[natt];
433
434 if (statts[i] == stfbi->visual->render_buffer)
435 pipe_resource_reference(&gsurf->render_texture, tex);
436
437 if (attachment_mask & (1 << natt)) {
438 /* transfer the ownership to the caller */
439 out[i] = tex;
440 attachment_mask &= ~(1 << natt);
441 }
442 else {
443 /* the attachment is listed more than once */
444 pipe_resource_reference(&out[i], tex);
445 }
446 }
447 }
448
449 return TRUE;
450 }
451
452 struct st_framebuffer_iface *
453 egl_g3d_create_st_framebuffer(_EGLSurface *surf)
454 {
455 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
456 struct st_framebuffer_iface *stfbi;
457
458 stfbi = CALLOC_STRUCT(st_framebuffer_iface);
459 if (!stfbi)
460 return NULL;
461
462 stfbi->visual = &gsurf->stvis;
463 if (gsurf->base.Type != EGL_PBUFFER_BIT) {
464 stfbi->flush_front = egl_g3d_st_framebuffer_flush_front;
465 stfbi->validate = egl_g3d_st_framebuffer_validate;
466 }
467 else {
468 stfbi->flush_front = egl_g3d_st_framebuffer_flush_front_pbuffer;
469 stfbi->validate = egl_g3d_st_framebuffer_validate_pbuffer;
470 }
471 stfbi->st_manager_private = (void *) &gsurf->base;
472
473 return stfbi;
474 }
475
476 void
477 egl_g3d_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi)
478 {
479 FREE(stfbi);
480 }