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