egl_g3d_st.c revision 2773f888dc9cde61dedf1b004e35efcc72ca9240
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
40struct egl_g3d_st_manager {
41   struct st_manager base;
42   _EGLDisplay *display;
43};
44
45static INLINE struct egl_g3d_st_manager *
46egl_g3d_st_manager(struct st_manager *smapi)
47{
48   return (struct egl_g3d_st_manager *) smapi;
49}
50
51static 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
57static EGLBoolean
58egl_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
73static boolean
74egl_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
106void
107egl_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
187void
188egl_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
207static boolean
208egl_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
238struct st_manager *
239egl_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
255void
256egl_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
262static boolean
263egl_g3d_st_framebuffer_flush_front_pbuffer(struct st_framebuffer_iface *stfbi,
264                                           enum st_attachment_type statt)
265{
266   return TRUE;
267}
268
269static boolean
270egl_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
309static boolean
310egl_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
319static boolean
320egl_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
404struct st_framebuffer_iface *
405egl_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
428void
429egl_g3d_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi)
430{
431   FREE(stfbi);
432}
433