xref: /aosp_15_r20/external/mesa3d/src/egl/drivers/haiku/egl_haiku.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 2014 Adrián Arroyo Calle <[email protected]>
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 #include <Bitmap.h>
53 
54 extern "C" {
55 #include "target-helpers/inline_sw_helper.h"
56 }
57 
58 #if MESA_DEBUG
59 #define TRACE(x...) printf("egl_haiku: " x)
60 #define CALLED()    TRACE("CALLED: %s\n", __PRETTY_FUNCTION__)
61 #else
62 #define TRACE(x...)
63 #define CALLED()
64 #endif
65 #define ERROR(x...) printf("egl_haiku: " x)
66 
67 _EGL_DRIVER_STANDARD_TYPECASTS(haiku_egl)
68 
69 struct haiku_egl_display {
70    int ref_count;
71    struct hgl_display *disp;
72 };
73 
74 struct haiku_egl_config {
75    _EGLConfig base;
76 };
77 
78 struct haiku_egl_context {
79    _EGLContext base;
80    struct hgl_context *ctx;
81 };
82 
83 struct haiku_egl_surface {
84    _EGLSurface base;
85    struct hgl_buffer *fb;
86    struct pipe_fence_handle *throttle_fence;
87 };
88 
89 // #pragma mark EGLSurface
90 
91 // Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
92 static _EGLSurface *
haiku_create_window_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)93 haiku_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
94                             void *native_window, const EGLint *attrib_list)
95 {
96    printf("haiku_create_window_surface\n");
97    struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
98 
99    struct haiku_egl_surface *wgl_surf =
100       (struct haiku_egl_surface *)calloc(1, sizeof(*wgl_surf));
101    if (!wgl_surf)
102       return NULL;
103 
104    if (!_eglInitSurface(&wgl_surf->base, disp, EGL_WINDOW_BIT, conf,
105                         attrib_list, NULL)) {
106       free(wgl_surf);
107       return NULL;
108    }
109 
110    struct st_visual visual;
111    hgl_get_st_visual(&visual, HGL_DOUBLE | HGL_DEPTH);
112 
113    wgl_surf->fb =
114       hgl_create_st_framebuffer(hgl_dpy->disp, &visual, native_window);
115    if (!wgl_surf->fb) {
116       free(wgl_surf);
117       return NULL;
118    }
119 
120    // Unset and delete previously set bitmap if any.
121    delete ((BitmapHook *)native_window)->SetBitmap(NULL);
122 
123    return &wgl_surf->base;
124 }
125 
126 static _EGLSurface *
haiku_create_pixmap_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_pixmap,const EGLint * attrib_list)127 haiku_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,
128                             void *native_pixmap, const EGLint *attrib_list)
129 {
130    printf("haiku_create_pixmap_surface\n");
131    return NULL;
132 }
133 
134 static _EGLSurface *
haiku_create_pbuffer_surface(_EGLDisplay * disp,_EGLConfig * conf,const EGLint * attrib_list)135 haiku_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,
136                              const EGLint *attrib_list)
137 {
138    printf("haiku_create_pbuffer_surface\n");
139    struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
140 
141    struct haiku_egl_surface *wgl_surf =
142       (struct haiku_egl_surface *)calloc(1, sizeof(*wgl_surf));
143    if (!wgl_surf)
144       return NULL;
145 
146    if (!_eglInitSurface(&wgl_surf->base, disp, EGL_PBUFFER_BIT, conf,
147                         attrib_list, NULL)) {
148       free(wgl_surf);
149       return NULL;
150    }
151 
152    struct st_visual visual;
153    hgl_get_st_visual(&visual, HGL_DOUBLE | HGL_DEPTH);
154 
155    wgl_surf->fb = hgl_create_st_framebuffer(hgl_dpy->disp, &visual, NULL);
156    if (!wgl_surf->fb) {
157       free(wgl_surf);
158       return NULL;
159    }
160 
161    wgl_surf->fb->newWidth = wgl_surf->base.Width;
162    wgl_surf->fb->newHeight = wgl_surf->base.Height;
163    p_atomic_inc(&wgl_surf->fb->base.stamp);
164 
165    return &wgl_surf->base;
166 }
167 
168 static EGLBoolean
haiku_destroy_surface(_EGLDisplay * disp,_EGLSurface * surf)169 haiku_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
170 {
171    struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
172    if (_eglPutSurface(surf)) {
173       struct haiku_egl_surface *hgl_surf = haiku_egl_surface(surf);
174       struct pipe_screen *screen = hgl_dpy->disp->fscreen->screen;
175       screen->fence_reference(screen, &hgl_surf->throttle_fence, NULL);
176 
177       // Unset bitmap to release ownership. Bitmap will be deleted later
178       // when destroying framebuffer.
179       BitmapHook *bitmapHook = (BitmapHook*)hgl_surf->fb->winsysContext;
180       if (bitmapHook != NULL)
181          bitmapHook->SetBitmap(NULL);
182 
183       hgl_destroy_st_framebuffer(hgl_surf->fb);
184       free(surf);
185    }
186    return EGL_TRUE;
187 }
188 
189 static void
update_size(struct hgl_buffer * buffer)190 update_size(struct hgl_buffer *buffer)
191 {
192    uint32_t newWidth, newHeight;
193    ((BitmapHook *)buffer->winsysContext)->GetSize(newWidth, newHeight);
194    if (buffer->newWidth != newWidth || buffer->newHeight != newHeight) {
195       buffer->newWidth = newWidth;
196       buffer->newHeight = newHeight;
197       p_atomic_inc(&buffer->base.stamp);
198    }
199 }
200 
201 static EGLBoolean
haiku_swap_buffers(_EGLDisplay * disp,_EGLSurface * surf)202 haiku_swap_buffers(_EGLDisplay *disp, _EGLSurface *surf)
203 {
204    struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
205    struct haiku_egl_surface *hgl_surf = haiku_egl_surface(surf);
206    struct haiku_egl_context *hgl_ctx = haiku_egl_context(surf->CurrentContext);
207    if (hgl_ctx == NULL)
208       return EGL_FALSE;
209 
210    struct st_context *st = hgl_ctx->ctx->st;
211    struct pipe_screen *screen = hgl_dpy->disp->fscreen->screen;
212 
213    struct hgl_buffer *buffer = hgl_surf->fb;
214    auto &frontBuffer = buffer->textures[ST_ATTACHMENT_FRONT_LEFT];
215    auto &backBuffer = buffer->textures[ST_ATTACHMENT_BACK_LEFT];
216 
217    // Inform ST of a flush if double buffering is used
218    if (backBuffer != NULL)
219       st->pipe->flush_resource(st->pipe, backBuffer);
220 
221    _mesa_glthread_finish(st->ctx);
222 
223    struct pipe_fence_handle *new_fence = NULL;
224    st_context_flush(st, ST_FLUSH_FRONT, &new_fence, NULL, NULL);
225    if (hgl_surf->throttle_fence) {
226       screen->fence_finish(screen, NULL, hgl_surf->throttle_fence,
227                            OS_TIMEOUT_INFINITE);
228       screen->fence_reference(screen, &hgl_surf->throttle_fence, NULL);
229    }
230    hgl_surf->throttle_fence = new_fence;
231 
232    // flush back buffer and swap buffers if double buffering is used
233    if (backBuffer != NULL) {
234       screen->flush_frontbuffer(screen, st->pipe, backBuffer, 0, 0,
235                                 buffer->winsysContext, 1, NULL);
236       std::swap(frontBuffer, backBuffer);
237       p_atomic_inc(&buffer->base.stamp);
238    }
239 
240    // XXX: right front / back if HGL_STEREO?
241 
242    update_size(buffer);
243 
244    st_context_invalidate_state(st, ST_INVALIDATE_FB_STATE);
245 
246    return EGL_TRUE;
247 }
248 
249 // #pragma mark EGLDisplay
250 
251 static EGLBoolean
haiku_add_configs_for_visuals(_EGLDisplay * disp)252 haiku_add_configs_for_visuals(_EGLDisplay *disp)
253 {
254    CALLED();
255 
256    struct haiku_egl_config *conf;
257    conf = (struct haiku_egl_config *)calloc(1, sizeof(*conf));
258    if (!conf)
259       return _eglError(EGL_BAD_ALLOC, "haiku_add_configs_for_visuals");
260 
261    _eglInitConfig(&conf->base, disp, 1);
262    TRACE("Config inited\n");
263 
264    conf->base.RedSize = 8;
265    conf->base.BlueSize = 8;
266    conf->base.GreenSize = 8;
267    conf->base.LuminanceSize = 0;
268    conf->base.AlphaSize = 8;
269    conf->base.ColorBufferType = EGL_RGB_BUFFER;
270    conf->base.BufferSize = conf->base.RedSize + conf->base.GreenSize +
271                            conf->base.BlueSize + conf->base.AlphaSize;
272    conf->base.ConfigCaveat = EGL_NONE;
273    conf->base.ConfigID = 1;
274    conf->base.BindToTextureRGB = EGL_FALSE;
275    conf->base.BindToTextureRGBA = EGL_FALSE;
276    conf->base.StencilSize = 0;
277    conf->base.TransparentType = EGL_NONE;
278    conf->base.NativeRenderable = EGL_TRUE; // Let's say yes
279    conf->base.NativeVisualID = 0;          // No visual
280    conf->base.NativeVisualType = EGL_NONE; // No visual
281    conf->base.RenderableType = 0x8;
282    conf->base.SampleBuffers = 0; // TODO: How to get the right value ?
283    conf->base.Samples = conf->base.SampleBuffers == 0 ? 0 : 0;
284    conf->base.DepthSize = 24; // TODO: How to get the right value ?
285    conf->base.Level = 0;
286    conf->base.MaxPbufferWidth = _EGL_MAX_PBUFFER_WIDTH;
287    conf->base.MaxPbufferHeight = _EGL_MAX_PBUFFER_HEIGHT;
288    conf->base.MaxPbufferPixels = 0; // TODO: How to get the right value ?
289    conf->base.SurfaceType = EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT;
290 
291    TRACE("Config configuated\n");
292    if (!_eglValidateConfig(&conf->base, EGL_FALSE)) {
293       _eglLog(_EGL_DEBUG, "Haiku: failed to validate config");
294       goto cleanup;
295    }
296    TRACE("Validated config\n");
297 
298    _eglLinkConfig(&conf->base);
299    if (!_eglGetArraySize(disp->Configs)) {
300       _eglLog(_EGL_WARNING, "Haiku: failed to create any config");
301       goto cleanup;
302    }
303    TRACE("Config successful\n");
304 
305    return EGL_TRUE;
306 
307 cleanup:
308    free(conf);
309    return EGL_FALSE;
310 }
311 
312 static void
haiku_display_destroy(_EGLDisplay * disp)313 haiku_display_destroy(_EGLDisplay *disp)
314 {
315    if (!disp)
316       return;
317 
318    struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
319 
320    assert(hgl_dpy->ref_count > 0);
321    if (!p_atomic_dec_zero(&hgl_dpy->ref_count))
322       return;
323 
324    struct pipe_screen *screen = hgl_dpy->disp->fscreen->screen;
325    hgl_destroy_display(hgl_dpy->disp);
326    hgl_dpy->disp = NULL;
327    screen->destroy(screen); // destroy will deallocate object
328 
329    free(hgl_dpy);
330 }
331 
332 static EGLBoolean
haiku_initialize_impl(_EGLDisplay * disp,void * platformDisplay)333 haiku_initialize_impl(_EGLDisplay *disp, void *platformDisplay)
334 {
335    struct haiku_egl_display *hgl_dpy;
336 
337    hgl_dpy =
338       (struct haiku_egl_display *)calloc(1, sizeof(struct haiku_egl_display));
339    if (!hgl_dpy)
340       return _eglError(EGL_BAD_ALLOC, "eglInitialize");
341 
342    hgl_dpy->ref_count = 1;
343    disp->DriverData = (void *)hgl_dpy;
344 
345    struct sw_winsys *winsys = hgl_create_sw_winsys();
346    struct pipe_screen *screen = sw_screen_create(winsys);
347    hgl_dpy->disp = hgl_create_display(screen);
348 
349    disp->ClientAPIs = 0;
350    if (_eglIsApiValid(EGL_OPENGL_API))
351       disp->ClientAPIs |= EGL_OPENGL_BIT;
352    if (_eglIsApiValid(EGL_OPENGL_ES_API))
353       disp->ClientAPIs |=
354          EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR;
355 
356    disp->Extensions.KHR_no_config_context = EGL_TRUE;
357    disp->Extensions.KHR_surfaceless_context = EGL_TRUE;
358    disp->Extensions.MESA_query_driver = EGL_TRUE;
359 
360    /* Report back to EGL the bitmask of priorities supported */
361    disp->Extensions.IMG_context_priority =
362       hgl_dpy->disp->fscreen->screen->get_param(hgl_dpy->disp->fscreen->screen,
363                                                 PIPE_CAP_CONTEXT_PRIORITY_MASK);
364 
365    disp->Extensions.EXT_pixel_format_float = EGL_TRUE;
366 
367    if (hgl_dpy->disp->fscreen->screen->is_format_supported(
368           hgl_dpy->disp->fscreen->screen, PIPE_FORMAT_B8G8R8A8_SRGB,
369           PIPE_TEXTURE_2D, 0, 0, PIPE_BIND_RENDER_TARGET))
370       disp->Extensions.KHR_gl_colorspace = EGL_TRUE;
371 
372    disp->Extensions.KHR_create_context = EGL_TRUE;
373    disp->Extensions.KHR_reusable_sync = EGL_TRUE;
374 
375    haiku_add_configs_for_visuals(disp);
376 
377    return EGL_TRUE;
378 }
379 
380 static EGLBoolean
haiku_initialize(_EGLDisplay * disp)381 haiku_initialize(_EGLDisplay *disp)
382 {
383    EGLBoolean ret = EGL_FALSE;
384    struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
385 
386    if (hgl_dpy) {
387       hgl_dpy->ref_count++;
388       return EGL_TRUE;
389    }
390 
391    switch (disp->Platform) {
392    case _EGL_PLATFORM_SURFACELESS:
393    case _EGL_PLATFORM_HAIKU:
394       ret = haiku_initialize_impl(disp, NULL);
395       break;
396    case _EGL_PLATFORM_DEVICE:
397       ret = haiku_initialize_impl(disp, disp->PlatformDisplay);
398       break;
399    default:
400       unreachable("Callers ensure we cannot get here.");
401       return EGL_FALSE;
402    }
403 
404    if (!ret)
405       return EGL_FALSE;
406 
407    hgl_dpy = haiku_egl_display(disp);
408 
409    return EGL_TRUE;
410 }
411 
412 static EGLBoolean
haiku_terminate(_EGLDisplay * disp)413 haiku_terminate(_EGLDisplay *disp)
414 {
415    haiku_display_destroy(disp);
416    return EGL_TRUE;
417 }
418 
419 // #pragma mark EGLContext
420 
421 static _EGLContext *
haiku_create_context(_EGLDisplay * disp,_EGLConfig * conf,_EGLContext * share_list,const EGLint * attrib_list)422 haiku_create_context(_EGLDisplay *disp, _EGLConfig *conf,
423                      _EGLContext *share_list, const EGLint *attrib_list)
424 {
425    CALLED();
426 
427    struct haiku_egl_display *hgl_dpy = haiku_egl_display(disp);
428 
429    struct st_visual visual;
430    hgl_get_st_visual(&visual, HGL_DOUBLE | HGL_DEPTH);
431 
432    struct haiku_egl_context *context =
433       (struct haiku_egl_context *)calloc(1, sizeof(*context));
434    if (!context) {
435       _eglError(EGL_BAD_ALLOC, "haiku_create_context");
436       return NULL;
437    }
438 
439    if (!_eglInitContext(&context->base, disp, conf, share_list, attrib_list))
440       goto cleanup;
441 
442    context->ctx = hgl_create_context(
443       hgl_dpy->disp, &visual,
444       share_list == NULL ? NULL : haiku_egl_context(share_list)->ctx->st);
445    if (context->ctx == NULL)
446       goto cleanup;
447 
448    return &context->base;
449 
450 cleanup:
451    free(context);
452    return NULL;
453 }
454 
455 static EGLBoolean
haiku_destroy_context(_EGLDisplay * disp,_EGLContext * ctx)456 haiku_destroy_context(_EGLDisplay *disp, _EGLContext *ctx)
457 {
458    if (_eglPutContext(ctx)) {
459       struct haiku_egl_context *hgl_ctx = haiku_egl_context(ctx);
460       hgl_destroy_context(hgl_ctx->ctx);
461       free(ctx);
462       ctx = NULL;
463    }
464    return EGL_TRUE;
465 }
466 
467 static EGLBoolean
haiku_make_current(_EGLDisplay * disp,_EGLSurface * dsurf,_EGLSurface * rsurf,_EGLContext * ctx)468 haiku_make_current(_EGLDisplay *disp, _EGLSurface *dsurf, _EGLSurface *rsurf,
469                    _EGLContext *ctx)
470 {
471    CALLED();
472 
473    struct haiku_egl_context *hgl_ctx = haiku_egl_context(ctx);
474    struct haiku_egl_surface *hgl_dsurf = haiku_egl_surface(dsurf);
475    struct haiku_egl_surface *hgl_rsurf = haiku_egl_surface(rsurf);
476    _EGLContext *old_ctx;
477    _EGLSurface *old_dsurf, *old_rsurf;
478 
479    if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf))
480       return EGL_FALSE;
481 
482    if (old_ctx == ctx && old_dsurf == dsurf && old_rsurf == rsurf) {
483       _eglPutSurface(old_dsurf);
484       _eglPutSurface(old_rsurf);
485       _eglPutContext(old_ctx);
486       return EGL_TRUE;
487    }
488 
489    if (ctx == NULL) {
490       st_api_make_current(NULL, NULL, NULL);
491    } else {
492       if (dsurf != NULL && dsurf != old_dsurf)
493          update_size(hgl_dsurf->fb);
494 
495       st_api_make_current(hgl_ctx->ctx->st,
496                           hgl_dsurf == NULL ? NULL : &hgl_dsurf->fb->base,
497                           hgl_rsurf == NULL ? NULL : &hgl_rsurf->fb->base);
498    }
499 
500    if (old_dsurf != NULL)
501       haiku_destroy_surface(disp, old_dsurf);
502    if (old_rsurf != NULL)
503       haiku_destroy_surface(disp, old_rsurf);
504    if (old_ctx != NULL)
505       haiku_destroy_context(disp, old_ctx);
506 
507    return EGL_TRUE;
508 }
509 
510 extern "C" const _EGLDriver _eglDriver = {
511    .Initialize = haiku_initialize,
512    .Terminate = haiku_terminate,
513    .CreateContext = haiku_create_context,
514    .DestroyContext = haiku_destroy_context,
515    .MakeCurrent = haiku_make_current,
516    .CreateWindowSurface = haiku_create_window_surface,
517    .CreatePixmapSurface = haiku_create_pixmap_surface,
518    .CreatePbufferSurface = haiku_create_pbuffer_surface,
519    .DestroySurface = haiku_destroy_surface,
520    .SwapBuffers = haiku_swap_buffers,
521 };
522