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