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