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