• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 2014 Adrián Arroyo Calle <adrian.arroyocalle@gmail.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include <dlfcn.h>
26 #include <errno.h>
27 #include <stdint.h>
28 #include <stdio.h>
29 
30 #include <algorithm>
31 
32 #include "eglconfig.h"
33 #include "eglcontext.h"
34 #include "eglcurrent.h"
35 #include "egldevice.h"
36 #include "egldisplay.h"
37 #include "egldriver.h"
38 #include "eglimage.h"
39 #include "egllog.h"
40 #include "eglsurface.h"
41 #include "egltypedefs.h"
42 
43 #include "pipe/p_context.h"
44 #include "pipe/p_defines.h"
45 #include "state_tracker/st_context.h"
46 #include "util/u_atomic.h"
47 #include <mapi/glapi/glapi.h>
48 
49 #include "hgl/hgl_sw_winsys.h"
50 #include "hgl_context.h"
51 
52 extern "C" {
53 #include "target-helpers/inline_sw_helper.h"
54 }
55 
56 #ifdef DEBUG
57 #define TRACE(x...) printf("egl_haiku: " x)
58 #define CALLED()    TRACE("CALLED: %s\n", __PRETTY_FUNCTION__)
59 #else
60 #define TRACE(x...)
61 #define CALLED()
62 #endif
63 #define ERROR(x...) printf("egl_haiku: " x)
64 
65 _EGL_DRIVER_STANDARD_TYPECASTS(haiku_egl)
66 
67 struct haiku_egl_display {
68    int ref_count;
69    struct hgl_display *disp;
70 };
71 
72 struct haiku_egl_config {
73    _EGLConfig base;
74 };
75 
76 struct haiku_egl_context {
77    _EGLContext base;
78    struct hgl_context *ctx;
79 };
80 
81 struct haiku_egl_surface {
82    _EGLSurface base;
83    struct hgl_buffer *fb;
84    struct pipe_fence_handle *throttle_fence;
85 };
86 
87 // #pragma mark EGLSurface
88 
89 // Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
90 static _EGLSurface *
haiku_create_window_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)91 haiku_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
92                             void *native_window, const EGLint *attrib_list)
93 {
94    printf("haiku_create_window_surface\n");
95    struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
96 
97    struct haiku_egl_surface *wgl_surf =
98       (struct haiku_egl_surface *)calloc(1, sizeof(*wgl_surf));
99    if (!wgl_surf)
100       return NULL;
101 
102    if (!_eglInitSurface(&wgl_surf->base, disp, EGL_WINDOW_BIT, conf,
103                         attrib_list, NULL)) {
104       free(wgl_surf);
105       return NULL;
106    }
107 
108    struct st_visual visual;
109    hgl_get_st_visual(&visual, HGL_DOUBLE | HGL_DEPTH);
110 
111    wgl_surf->fb =
112       hgl_create_st_framebuffer(hgl_dpy->disp, &visual, native_window);
113    if (!wgl_surf->fb) {
114       free(wgl_surf);
115       return NULL;
116    }
117 
118    return &wgl_surf->base;
119 }
120 
121 static _EGLSurface *
haiku_create_pixmap_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_pixmap,const EGLint * attrib_list)122 haiku_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,
123                             void *native_pixmap, const EGLint *attrib_list)
124 {
125    printf("haiku_create_pixmap_surface\n");
126    return NULL;
127 }
128 
129 static _EGLSurface *
haiku_create_pbuffer_surface(_EGLDisplay * disp,_EGLConfig * conf,const EGLint * attrib_list)130 haiku_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,
131                              const EGLint *attrib_list)
132 {
133    printf("haiku_create_pbuffer_surface\n");
134    struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
135 
136    struct haiku_egl_surface *wgl_surf =
137       (struct haiku_egl_surface *)calloc(1, sizeof(*wgl_surf));
138    if (!wgl_surf)
139       return NULL;
140 
141    if (!_eglInitSurface(&wgl_surf->base, disp, EGL_PBUFFER_BIT, conf,
142                         attrib_list, NULL)) {
143       free(wgl_surf);
144       return NULL;
145    }
146 
147    struct st_visual visual;
148    hgl_get_st_visual(&visual, HGL_DOUBLE | HGL_DEPTH);
149 
150    wgl_surf->fb = hgl_create_st_framebuffer(hgl_dpy->disp, &visual, NULL);
151    if (!wgl_surf->fb) {
152       free(wgl_surf);
153       return NULL;
154    }
155 
156    wgl_surf->fb->newWidth = wgl_surf->base.Width;
157    wgl_surf->fb->newHeight = wgl_surf->base.Height;
158    p_atomic_inc(&wgl_surf->fb->base.stamp);
159 
160    return &wgl_surf->base;
161 }
162 
163 static EGLBoolean
haiku_destroy_surface(_EGLDisplay * disp,_EGLSurface * surf)164 haiku_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
165 {
166    struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
167    if (_eglPutSurface(surf)) {
168       struct haiku_egl_surface *hgl_surf = haiku_egl_surface(surf);
169       struct pipe_screen *screen = hgl_dpy->disp->fscreen->screen;
170       screen->fence_reference(screen, &hgl_surf->throttle_fence, NULL);
171       hgl_destroy_st_framebuffer(hgl_surf->fb);
172       free(surf);
173    }
174    return EGL_TRUE;
175 }
176 
177 static void
update_size(struct hgl_buffer * buffer)178 update_size(struct hgl_buffer *buffer)
179 {
180    uint32_t newWidth, newHeight;
181    ((BitmapHook *)buffer->winsysContext)->GetSize(newWidth, newHeight);
182    if (buffer->newWidth != newWidth || buffer->newHeight != newHeight) {
183       buffer->newWidth = newWidth;
184       buffer->newHeight = newHeight;
185       p_atomic_inc(&buffer->base.stamp);
186    }
187 }
188 
189 static EGLBoolean
haiku_swap_buffers(_EGLDisplay * disp,_EGLSurface * surf)190 haiku_swap_buffers(_EGLDisplay *disp, _EGLSurface *surf)
191 {
192    struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
193    struct haiku_egl_surface *hgl_surf = haiku_egl_surface(surf);
194    struct haiku_egl_context *hgl_ctx = haiku_egl_context(surf->CurrentContext);
195    if (hgl_ctx == NULL)
196       return EGL_FALSE;
197 
198    struct st_context *st = hgl_ctx->ctx->st;
199    struct pipe_screen *screen = hgl_dpy->disp->fscreen->screen;
200 
201    struct hgl_buffer *buffer = hgl_surf->fb;
202    auto &frontBuffer = buffer->textures[ST_ATTACHMENT_FRONT_LEFT];
203    auto &backBuffer = buffer->textures[ST_ATTACHMENT_BACK_LEFT];
204 
205    // Inform ST of a flush if double buffering is used
206    if (backBuffer != NULL)
207       st->pipe->flush_resource(st->pipe, backBuffer);
208 
209    _mesa_glthread_finish(st->ctx);
210 
211    struct pipe_fence_handle *new_fence = NULL;
212    st_context_flush(st, ST_FLUSH_FRONT, &new_fence, NULL, NULL);
213    if (hgl_surf->throttle_fence) {
214       screen->fence_finish(screen, NULL, hgl_surf->throttle_fence,
215                            OS_TIMEOUT_INFINITE);
216       screen->fence_reference(screen, &hgl_surf->throttle_fence, NULL);
217    }
218    hgl_surf->throttle_fence = new_fence;
219 
220    // flush back buffer and swap buffers if double buffering is used
221    if (backBuffer != NULL) {
222       screen->flush_frontbuffer(screen, st->pipe, backBuffer, 0, 0,
223                                 buffer->winsysContext, NULL);
224       std::swap(frontBuffer, backBuffer);
225       p_atomic_inc(&buffer->base.stamp);
226    }
227 
228    // XXX: right front / back if HGL_STEREO?
229 
230    update_size(buffer);
231 
232    return EGL_TRUE;
233 }
234 
235 // #pragma mark EGLDisplay
236 
237 static EGLBoolean
haiku_add_configs_for_visuals(_EGLDisplay * disp)238 haiku_add_configs_for_visuals(_EGLDisplay *disp)
239 {
240    CALLED();
241 
242    struct haiku_egl_config *conf;
243    conf = (struct haiku_egl_config *)calloc(1, sizeof(*conf));
244    if (!conf)
245       return _eglError(EGL_BAD_ALLOC, "haiku_add_configs_for_visuals");
246 
247    _eglInitConfig(&conf->base, disp, 1);
248    TRACE("Config inited\n");
249 
250    conf->base.RedSize = 8;
251    conf->base.BlueSize = 8;
252    conf->base.GreenSize = 8;
253    conf->base.LuminanceSize = 0;
254    conf->base.AlphaSize = 8;
255    conf->base.ColorBufferType = EGL_RGB_BUFFER;
256    conf->base.BufferSize = conf->base.RedSize + conf->base.GreenSize +
257                            conf->base.BlueSize + conf->base.AlphaSize;
258    conf->base.ConfigCaveat = EGL_NONE;
259    conf->base.ConfigID = 1;
260    conf->base.BindToTextureRGB = EGL_FALSE;
261    conf->base.BindToTextureRGBA = EGL_FALSE;
262    conf->base.StencilSize = 0;
263    conf->base.TransparentType = EGL_NONE;
264    conf->base.NativeRenderable = EGL_TRUE; // Let's say yes
265    conf->base.NativeVisualID = 0;          // No visual
266    conf->base.NativeVisualType = EGL_NONE; // No visual
267    conf->base.RenderableType = 0x8;
268    conf->base.SampleBuffers = 0; // TODO: How to get the right value ?
269    conf->base.Samples = conf->base.SampleBuffers == 0 ? 0 : 0;
270    conf->base.DepthSize = 24; // TODO: How to get the right value ?
271    conf->base.Level = 0;
272    conf->base.MaxPbufferWidth = _EGL_MAX_PBUFFER_WIDTH;
273    conf->base.MaxPbufferHeight = _EGL_MAX_PBUFFER_HEIGHT;
274    conf->base.MaxPbufferPixels = 0; // TODO: How to get the right value ?
275    conf->base.SurfaceType = EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT;
276 
277    TRACE("Config configuated\n");
278    if (!_eglValidateConfig(&conf->base, EGL_FALSE)) {
279       _eglLog(_EGL_DEBUG, "Haiku: failed to validate config");
280       goto cleanup;
281    }
282    TRACE("Validated config\n");
283 
284    _eglLinkConfig(&conf->base);
285    if (!_eglGetArraySize(disp->Configs)) {
286       _eglLog(_EGL_WARNING, "Haiku: failed to create any config");
287       goto cleanup;
288    }
289    TRACE("Config successful\n");
290 
291    return EGL_TRUE;
292 
293 cleanup:
294    free(conf);
295    return EGL_FALSE;
296 }
297 
298 static void
haiku_display_destroy(_EGLDisplay * disp)299 haiku_display_destroy(_EGLDisplay *disp)
300 {
301    if (!disp)
302       return;
303 
304    struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
305 
306    assert(hgl_dpy->ref_count > 0);
307    if (!p_atomic_dec_zero(&hgl_dpy->ref_count))
308       return;
309 
310    struct pipe_screen *screen = hgl_dpy->disp->fscreen->screen;
311    hgl_destroy_display(hgl_dpy->disp);
312    hgl_dpy->disp = NULL;
313    screen->destroy(screen); // destroy will deallocate object
314 
315    free(hgl_dpy);
316 }
317 
318 static EGLBoolean
haiku_initialize_impl(_EGLDisplay * disp,void * platformDisplay)319 haiku_initialize_impl(_EGLDisplay *disp, void *platformDisplay)
320 {
321    struct haiku_egl_display *hgl_dpy;
322 
323    hgl_dpy =
324       (struct haiku_egl_display *)calloc(1, sizeof(struct haiku_egl_display));
325    if (!hgl_dpy)
326       return _eglError(EGL_BAD_ALLOC, "eglInitialize");
327 
328    hgl_dpy->ref_count = 1;
329    disp->DriverData = (void *)hgl_dpy;
330 
331    struct sw_winsys *winsys = hgl_create_sw_winsys();
332    struct pipe_screen *screen = sw_screen_create(winsys);
333    hgl_dpy->disp = hgl_create_display(screen);
334 
335    disp->ClientAPIs = 0;
336    if (_eglIsApiValid(EGL_OPENGL_API))
337       disp->ClientAPIs |= EGL_OPENGL_BIT;
338    if (_eglIsApiValid(EGL_OPENGL_ES_API))
339       disp->ClientAPIs |=
340          EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR;
341 
342    disp->Extensions.KHR_no_config_context = EGL_TRUE;
343    disp->Extensions.KHR_surfaceless_context = EGL_TRUE;
344    disp->Extensions.MESA_query_driver = EGL_TRUE;
345 
346    /* Report back to EGL the bitmask of priorities supported */
347    disp->Extensions.IMG_context_priority =
348       hgl_dpy->disp->fscreen->screen->get_param(hgl_dpy->disp->fscreen->screen,
349                                                 PIPE_CAP_CONTEXT_PRIORITY_MASK);
350 
351    disp->Extensions.EXT_pixel_format_float = EGL_TRUE;
352 
353    if (hgl_dpy->disp->fscreen->screen->is_format_supported(
354           hgl_dpy->disp->fscreen->screen, PIPE_FORMAT_B8G8R8A8_SRGB,
355           PIPE_TEXTURE_2D, 0, 0, PIPE_BIND_RENDER_TARGET))
356       disp->Extensions.KHR_gl_colorspace = EGL_TRUE;
357 
358    disp->Extensions.KHR_create_context = EGL_TRUE;
359    disp->Extensions.KHR_reusable_sync = EGL_TRUE;
360 
361    haiku_add_configs_for_visuals(disp);
362 
363    return EGL_TRUE;
364 }
365 
366 static EGLBoolean
haiku_initialize(_EGLDisplay * disp)367 haiku_initialize(_EGLDisplay *disp)
368 {
369    EGLBoolean ret = EGL_FALSE;
370    struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
371 
372    if (hgl_dpy) {
373       hgl_dpy->ref_count++;
374       return EGL_TRUE;
375    }
376 
377    switch (disp->Platform) {
378    case _EGL_PLATFORM_SURFACELESS:
379    case _EGL_PLATFORM_HAIKU:
380       ret = haiku_initialize_impl(disp, NULL);
381       break;
382    case _EGL_PLATFORM_DEVICE:
383       ret = haiku_initialize_impl(disp, disp->PlatformDisplay);
384       break;
385    default:
386       unreachable("Callers ensure we cannot get here.");
387       return EGL_FALSE;
388    }
389 
390    if (!ret)
391       return EGL_FALSE;
392 
393    hgl_dpy = haiku_egl_display(disp);
394 
395    return EGL_TRUE;
396 }
397 
398 static EGLBoolean
haiku_terminate(_EGLDisplay * disp)399 haiku_terminate(_EGLDisplay *disp)
400 {
401    haiku_display_destroy(disp);
402    return EGL_TRUE;
403 }
404 
405 // #pragma mark EGLContext
406 
407 static _EGLContext *
haiku_create_context(_EGLDisplay * disp,_EGLConfig * conf,_EGLContext * share_list,const EGLint * attrib_list)408 haiku_create_context(_EGLDisplay *disp, _EGLConfig *conf,
409                      _EGLContext *share_list, const EGLint *attrib_list)
410 {
411    CALLED();
412 
413    struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
414 
415    struct st_visual visual;
416    hgl_get_st_visual(&visual, HGL_DOUBLE | HGL_DEPTH);
417 
418    struct haiku_egl_context *context =
419       (struct haiku_egl_context *)calloc(1, sizeof(*context));
420    if (!context) {
421       _eglError(EGL_BAD_ALLOC, "haiku_create_context");
422       return NULL;
423    }
424 
425    if (!_eglInitContext(&context->base, disp, conf, share_list, attrib_list))
426       goto cleanup;
427 
428    context->ctx = hgl_create_context(
429       hgl_dpy->disp, &visual,
430       share_list == NULL ? NULL : haiku_egl_context(share_list)->ctx->st);
431    if (context->ctx == NULL)
432       goto cleanup;
433 
434    return &context->base;
435 
436 cleanup:
437    free(context);
438    return NULL;
439 }
440 
441 static EGLBoolean
haiku_destroy_context(_EGLDisplay * disp,_EGLContext * ctx)442 haiku_destroy_context(_EGLDisplay *disp, _EGLContext *ctx)
443 {
444    if (_eglPutContext(ctx)) {
445       struct haiku_egl_context *hgl_ctx = haiku_egl_context(ctx);
446       hgl_destroy_context(hgl_ctx->ctx);
447       free(ctx);
448       ctx = NULL;
449    }
450    return EGL_TRUE;
451 }
452 
453 static EGLBoolean
haiku_make_current(_EGLDisplay * disp,_EGLSurface * dsurf,_EGLSurface * rsurf,_EGLContext * ctx)454 haiku_make_current(_EGLDisplay *disp, _EGLSurface *dsurf, _EGLSurface *rsurf,
455                    _EGLContext *ctx)
456 {
457    CALLED();
458 
459    struct haiku_egl_context *hgl_ctx = haiku_egl_context(ctx);
460    struct haiku_egl_surface *hgl_dsurf = haiku_egl_surface(dsurf);
461    struct haiku_egl_surface *hgl_rsurf = haiku_egl_surface(rsurf);
462    _EGLContext *old_ctx;
463    _EGLSurface *old_dsurf, *old_rsurf;
464 
465    if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf))
466       return EGL_FALSE;
467 
468    if (old_ctx == ctx && old_dsurf == dsurf && old_rsurf == rsurf) {
469       _eglPutSurface(old_dsurf);
470       _eglPutSurface(old_rsurf);
471       _eglPutContext(old_ctx);
472       return EGL_TRUE;
473    }
474 
475    if (ctx == NULL) {
476       st_api_make_current(NULL, NULL, NULL);
477    } else {
478       if (dsurf != NULL && dsurf != old_dsurf)
479          update_size(hgl_dsurf->fb);
480 
481       st_api_make_current(hgl_ctx->ctx->st,
482                           hgl_dsurf == NULL ? NULL : &hgl_dsurf->fb->base,
483                           hgl_rsurf == NULL ? NULL : &hgl_rsurf->fb->base);
484    }
485 
486    if (old_dsurf != NULL)
487       haiku_destroy_surface(disp, old_dsurf);
488    if (old_rsurf != NULL)
489       haiku_destroy_surface(disp, old_rsurf);
490    if (old_ctx != NULL)
491       haiku_destroy_context(disp, old_ctx);
492 
493    return EGL_TRUE;
494 }
495 
496 extern "C" const _EGLDriver _eglDriver = {
497    .Initialize = haiku_initialize,
498    .Terminate = haiku_terminate,
499    .CreateContext = haiku_create_context,
500    .DestroyContext = haiku_destroy_context,
501    .MakeCurrent = haiku_make_current,
502    .CreateWindowSurface = haiku_create_window_surface,
503    .CreatePixmapSurface = haiku_create_pixmap_surface,
504    .CreatePbufferSurface = haiku_create_pbuffer_surface,
505    .DestroySurface = haiku_destroy_surface,
506    .SwapBuffers = haiku_swap_buffers,
507 };
508