Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 1 | /* |
| 2 | * Mesa 3-D graphics library |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 3 | * |
| 4 | * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com> |
| 5 | * Copyright (C) 2010-2011 LunarG Inc. |
| 6 | * |
| 7 | * Based on platform_x11, which has |
| 8 | * |
| 9 | * Copyright © 2011 Intel Corporation |
| 10 | * |
| 11 | * Permission is hereby granted, free of charge, to any person obtaining a |
| 12 | * copy of this software and associated documentation files (the "Software"), |
| 13 | * to deal in the Software without restriction, including without limitation |
| 14 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 15 | * and/or sell copies of the Software, and to permit persons to whom the |
| 16 | * Software is furnished to do so, subject to the following conditions: |
| 17 | * |
| 18 | * The above copyright notice and this permission notice shall be included |
| 19 | * in all copies or substantial portions of the Software. |
| 20 | * |
| 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 24 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| 26 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| 27 | * DEALINGS IN THE SOFTWARE. |
| 28 | */ |
| 29 | |
| 30 | #include <errno.h> |
| 31 | #include <dlfcn.h> |
| 32 | |
Chad Versace | bfe28b8 | 2012-12-20 14:16:50 -0800 | [diff] [blame] | 33 | #if ANDROID_VERSION >= 0x402 |
| 34 | #include <sync/sync.h> |
| 35 | #endif |
| 36 | |
Emil Velikov | 8d4357b | 2014-01-11 04:52:48 +0000 | [diff] [blame] | 37 | #include "loader.h" |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 38 | #include "egl_dri2.h" |
Chad Versace | 8b9298a | 2014-01-28 12:34:19 -0800 | [diff] [blame] | 39 | #include "egl_dri2_fallbacks.h" |
Tapani Pälli | 4070295 | 2013-01-24 09:56:47 +0200 | [diff] [blame] | 40 | #include "gralloc_drm.h" |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 41 | |
| 42 | static int |
| 43 | get_format_bpp(int native) |
| 44 | { |
| 45 | int bpp; |
| 46 | |
| 47 | switch (native) { |
| 48 | case HAL_PIXEL_FORMAT_RGBA_8888: |
| 49 | case HAL_PIXEL_FORMAT_RGBX_8888: |
| 50 | case HAL_PIXEL_FORMAT_BGRA_8888: |
| 51 | bpp = 4; |
| 52 | break; |
| 53 | case HAL_PIXEL_FORMAT_RGB_888: |
| 54 | bpp = 3; |
| 55 | break; |
| 56 | case HAL_PIXEL_FORMAT_RGB_565: |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 57 | bpp = 2; |
| 58 | break; |
| 59 | default: |
| 60 | bpp = 0; |
| 61 | break; |
| 62 | } |
| 63 | |
| 64 | return bpp; |
| 65 | } |
| 66 | |
| 67 | static int |
Chia-I Wu | 75cc24c | 2011-11-25 11:59:02 +0800 | [diff] [blame] | 68 | get_native_buffer_name(struct ANativeWindowBuffer *buf) |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 69 | { |
Tapani Pälli | 4070295 | 2013-01-24 09:56:47 +0200 | [diff] [blame] | 70 | return gralloc_drm_get_gem_handle(buf->handle); |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 71 | } |
| 72 | |
| 73 | static EGLBoolean |
| 74 | droid_window_dequeue_buffer(struct dri2_egl_surface *dri2_surf) |
| 75 | { |
Chad Versace | bfe28b8 | 2012-12-20 14:16:50 -0800 | [diff] [blame] | 76 | #if ANDROID_VERSION >= 0x0402 |
| 77 | int fence_fd; |
| 78 | |
| 79 | if (dri2_surf->window->dequeueBuffer(dri2_surf->window, &dri2_surf->buffer, |
| 80 | &fence_fd)) |
| 81 | return EGL_FALSE; |
| 82 | |
| 83 | /* If access to the buffer is controlled by a sync fence, then block on the |
| 84 | * fence. |
| 85 | * |
| 86 | * It may be more performant to postpone blocking until there is an |
| 87 | * immediate need to write to the buffer. But doing so would require adding |
| 88 | * hooks to the DRI2 loader. |
| 89 | * |
| 90 | * From the ANativeWindow::dequeueBuffer documentation: |
| 91 | * |
| 92 | * The libsync fence file descriptor returned in the int pointed to by |
| 93 | * the fenceFd argument will refer to the fence that must signal |
| 94 | * before the dequeued buffer may be written to. A value of -1 |
| 95 | * indicates that the caller may access the buffer immediately without |
| 96 | * waiting on a fence. If a valid file descriptor is returned (i.e. |
| 97 | * any value except -1) then the caller is responsible for closing the |
| 98 | * file descriptor. |
| 99 | */ |
| 100 | if (fence_fd >= 0) { |
| 101 | /* From the SYNC_IOC_WAIT documentation in <linux/sync.h>: |
| 102 | * |
| 103 | * Waits indefinitely if timeout < 0. |
| 104 | */ |
| 105 | int timeout = -1; |
| 106 | sync_wait(fence_fd, timeout); |
| 107 | close(fence_fd); |
| 108 | } |
| 109 | |
| 110 | dri2_surf->buffer->common.incRef(&dri2_surf->buffer->common); |
| 111 | #else |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 112 | if (dri2_surf->window->dequeueBuffer(dri2_surf->window, &dri2_surf->buffer)) |
| 113 | return EGL_FALSE; |
| 114 | |
| 115 | dri2_surf->buffer->common.incRef(&dri2_surf->buffer->common); |
| 116 | dri2_surf->window->lockBuffer(dri2_surf->window, dri2_surf->buffer); |
Chad Versace | bfe28b8 | 2012-12-20 14:16:50 -0800 | [diff] [blame] | 117 | #endif |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 118 | |
| 119 | return EGL_TRUE; |
| 120 | } |
| 121 | |
| 122 | static EGLBoolean |
| 123 | droid_window_enqueue_buffer(struct dri2_egl_surface *dri2_surf) |
| 124 | { |
Chad Versace | bfe28b8 | 2012-12-20 14:16:50 -0800 | [diff] [blame] | 125 | #if ANDROID_VERSION >= 0x0402 |
| 126 | /* Queue the buffer without a sync fence. This informs the ANativeWindow |
| 127 | * that it may access the buffer immediately. |
| 128 | * |
| 129 | * From ANativeWindow::dequeueBuffer: |
| 130 | * |
| 131 | * The fenceFd argument specifies a libsync fence file descriptor for |
| 132 | * a fence that must signal before the buffer can be accessed. If |
| 133 | * the buffer can be accessed immediately then a value of -1 should |
| 134 | * be used. The caller must not use the file descriptor after it |
| 135 | * is passed to queueBuffer, and the ANativeWindow implementation |
| 136 | * is responsible for closing it. |
| 137 | */ |
| 138 | int fence_fd = -1; |
| 139 | dri2_surf->window->queueBuffer(dri2_surf->window, dri2_surf->buffer, |
| 140 | fence_fd); |
| 141 | #else |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 142 | dri2_surf->window->queueBuffer(dri2_surf->window, dri2_surf->buffer); |
Chad Versace | bfe28b8 | 2012-12-20 14:16:50 -0800 | [diff] [blame] | 143 | #endif |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 144 | |
| 145 | dri2_surf->buffer->common.decRef(&dri2_surf->buffer->common); |
| 146 | dri2_surf->buffer = NULL; |
| 147 | |
| 148 | return EGL_TRUE; |
| 149 | } |
| 150 | |
| 151 | static void |
| 152 | droid_window_cancel_buffer(struct dri2_egl_surface *dri2_surf) |
| 153 | { |
| 154 | /* no cancel buffer? */ |
| 155 | droid_window_enqueue_buffer(dri2_surf); |
| 156 | } |
| 157 | |
| 158 | static __DRIbuffer * |
| 159 | droid_alloc_local_buffer(struct dri2_egl_surface *dri2_surf, |
| 160 | unsigned int att, unsigned int format) |
| 161 | { |
| 162 | struct dri2_egl_display *dri2_dpy = |
| 163 | dri2_egl_display(dri2_surf->base.Resource.Display); |
| 164 | |
| 165 | if (att >= ARRAY_SIZE(dri2_surf->local_buffers)) |
| 166 | return NULL; |
| 167 | |
| 168 | if (!dri2_surf->local_buffers[att]) { |
| 169 | dri2_surf->local_buffers[att] = |
| 170 | dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, att, format, |
| 171 | dri2_surf->base.Width, dri2_surf->base.Height); |
| 172 | } |
| 173 | |
| 174 | return dri2_surf->local_buffers[att]; |
| 175 | } |
| 176 | |
| 177 | static void |
| 178 | droid_free_local_buffers(struct dri2_egl_surface *dri2_surf) |
| 179 | { |
| 180 | struct dri2_egl_display *dri2_dpy = |
| 181 | dri2_egl_display(dri2_surf->base.Resource.Display); |
| 182 | int i; |
| 183 | |
| 184 | for (i = 0; i < ARRAY_SIZE(dri2_surf->local_buffers); i++) { |
| 185 | if (dri2_surf->local_buffers[i]) { |
| 186 | dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, |
| 187 | dri2_surf->local_buffers[i]); |
| 188 | dri2_surf->local_buffers[i] = NULL; |
| 189 | } |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | static _EGLSurface * |
| 194 | droid_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, |
Chad Versace | 6d1f83e | 2014-01-07 14:54:51 -0800 | [diff] [blame] | 195 | _EGLConfig *conf, void *native_window, |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 196 | const EGLint *attrib_list) |
| 197 | { |
| 198 | struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); |
| 199 | struct dri2_egl_config *dri2_conf = dri2_egl_config(conf); |
| 200 | struct dri2_egl_surface *dri2_surf; |
Chad Versace | 6d1f83e | 2014-01-07 14:54:51 -0800 | [diff] [blame] | 201 | struct ANativeWindow *window = native_window; |
| 202 | |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 203 | dri2_surf = calloc(1, sizeof *dri2_surf); |
| 204 | if (!dri2_surf) { |
| 205 | _eglError(EGL_BAD_ALLOC, "droid_create_surface"); |
| 206 | return NULL; |
| 207 | } |
| 208 | |
| 209 | if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list)) |
Chia-I Wu | c8e18f8 | 2011-08-26 22:09:56 +0800 | [diff] [blame] | 210 | goto cleanup_surface; |
| 211 | |
| 212 | if (type == EGL_WINDOW_BIT) { |
| 213 | int format; |
| 214 | |
| 215 | if (!window || window->common.magic != ANDROID_NATIVE_WINDOW_MAGIC) { |
| 216 | _eglError(EGL_BAD_NATIVE_WINDOW, "droid_create_surface"); |
| 217 | goto cleanup_surface; |
| 218 | } |
| 219 | if (window->query(window, NATIVE_WINDOW_FORMAT, &format)) { |
| 220 | _eglError(EGL_BAD_NATIVE_WINDOW, "droid_create_surface"); |
| 221 | goto cleanup_surface; |
| 222 | } |
| 223 | |
| 224 | if (format != dri2_conf->base.NativeVisualID) { |
| 225 | _eglLog(_EGL_WARNING, "Native format mismatch: 0x%x != 0x%x", |
| 226 | format, dri2_conf->base.NativeVisualID); |
| 227 | } |
| 228 | |
| 229 | window->query(window, NATIVE_WINDOW_WIDTH, &dri2_surf->base.Width); |
| 230 | window->query(window, NATIVE_WINDOW_HEIGHT, &dri2_surf->base.Height); |
| 231 | } |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 232 | |
| 233 | dri2_surf->dri_drawable = |
| 234 | (*dri2_dpy->dri2->createNewDrawable)(dri2_dpy->dri_screen, |
| 235 | dri2_conf->dri_double_config, |
| 236 | dri2_surf); |
| 237 | if (dri2_surf->dri_drawable == NULL) { |
| 238 | _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable"); |
Chia-I Wu | c8e18f8 | 2011-08-26 22:09:56 +0800 | [diff] [blame] | 239 | goto cleanup_surface; |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 240 | } |
| 241 | |
Chia-I Wu | c8e18f8 | 2011-08-26 22:09:56 +0800 | [diff] [blame] | 242 | if (window) { |
| 243 | window->common.incRef(&window->common); |
| 244 | dri2_surf->window = window; |
| 245 | } |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 246 | |
| 247 | return &dri2_surf->base; |
| 248 | |
Chia-I Wu | c8e18f8 | 2011-08-26 22:09:56 +0800 | [diff] [blame] | 249 | cleanup_surface: |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 250 | free(dri2_surf); |
| 251 | |
| 252 | return NULL; |
| 253 | } |
| 254 | |
| 255 | static _EGLSurface * |
| 256 | droid_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, |
Chad Versace | 6d1f83e | 2014-01-07 14:54:51 -0800 | [diff] [blame] | 257 | _EGLConfig *conf, void *native_window, |
| 258 | const EGLint *attrib_list) |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 259 | { |
| 260 | return droid_create_surface(drv, disp, EGL_WINDOW_BIT, conf, |
Chad Versace | 6d1f83e | 2014-01-07 14:54:51 -0800 | [diff] [blame] | 261 | native_window, attrib_list); |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 262 | } |
| 263 | |
| 264 | static _EGLSurface * |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 265 | droid_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp, |
| 266 | _EGLConfig *conf, const EGLint *attrib_list) |
| 267 | { |
Chia-I Wu | 93d5963 | 2011-08-27 00:00:18 +0800 | [diff] [blame] | 268 | return droid_create_surface(drv, disp, EGL_PBUFFER_BIT, conf, |
| 269 | NULL, attrib_list); |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 270 | } |
| 271 | |
| 272 | static EGLBoolean |
| 273 | droid_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) |
| 274 | { |
| 275 | struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); |
| 276 | struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); |
| 277 | |
| 278 | if (!_eglPutSurface(surf)) |
| 279 | return EGL_TRUE; |
| 280 | |
| 281 | droid_free_local_buffers(dri2_surf); |
| 282 | |
Chia-I Wu | c8e18f8 | 2011-08-26 22:09:56 +0800 | [diff] [blame] | 283 | if (dri2_surf->base.Type == EGL_WINDOW_BIT) { |
| 284 | if (dri2_surf->buffer) |
| 285 | droid_window_cancel_buffer(dri2_surf); |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 286 | |
Chia-I Wu | c8e18f8 | 2011-08-26 22:09:56 +0800 | [diff] [blame] | 287 | dri2_surf->window->common.decRef(&dri2_surf->window->common); |
| 288 | } |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 289 | |
| 290 | (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable); |
| 291 | |
| 292 | free(dri2_surf); |
| 293 | |
| 294 | return EGL_TRUE; |
| 295 | } |
| 296 | |
| 297 | static EGLBoolean |
| 298 | droid_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) |
| 299 | { |
| 300 | struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); |
| 301 | struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); |
| 302 | struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); |
| 303 | _EGLContext *ctx; |
| 304 | |
Chia-I Wu | c8e18f8 | 2011-08-26 22:09:56 +0800 | [diff] [blame] | 305 | if (dri2_surf->base.Type != EGL_WINDOW_BIT) |
| 306 | return EGL_TRUE; |
| 307 | |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 308 | if (dri2_drv->glFlush) { |
| 309 | ctx = _eglGetCurrentContext(); |
| 310 | if (ctx && ctx->DrawSurface == &dri2_surf->base) |
| 311 | dri2_drv->glFlush(); |
| 312 | } |
| 313 | |
Eric Anholt | 70e8ccc | 2014-12-21 11:51:33 -0800 | [diff] [blame^] | 314 | dri2_flush_drawable_for_swapbuffers(disp, draw); |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 315 | |
| 316 | if (dri2_surf->buffer) |
| 317 | droid_window_enqueue_buffer(dri2_surf); |
| 318 | |
| 319 | (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable); |
| 320 | |
| 321 | return EGL_TRUE; |
| 322 | } |
| 323 | |
| 324 | static _EGLImage * |
Chad Versace | 2878f46 | 2013-05-06 07:41:11 -0700 | [diff] [blame] | 325 | dri2_create_image_android_native_buffer(_EGLDisplay *disp, _EGLContext *ctx, |
Chia-I Wu | 75cc24c | 2011-11-25 11:59:02 +0800 | [diff] [blame] | 326 | struct ANativeWindowBuffer *buf) |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 327 | { |
| 328 | struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); |
| 329 | struct dri2_egl_image *dri2_img; |
| 330 | int name; |
| 331 | EGLint format; |
| 332 | |
Chad Versace | 2878f46 | 2013-05-06 07:41:11 -0700 | [diff] [blame] | 333 | if (ctx != NULL) { |
| 334 | /* From the EGL_ANDROID_image_native_buffer spec: |
| 335 | * |
| 336 | * * If <target> is EGL_NATIVE_BUFFER_ANDROID and <ctx> is not |
| 337 | * EGL_NO_CONTEXT, the error EGL_BAD_CONTEXT is generated. |
| 338 | */ |
| 339 | _eglError(EGL_BAD_CONTEXT, "eglCreateEGLImageKHR: for " |
| 340 | "EGL_NATIVE_BUFFER_ANDROID, the context must be " |
| 341 | "EGL_NO_CONTEXT"); |
| 342 | return NULL; |
| 343 | } |
| 344 | |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 345 | if (!buf || buf->common.magic != ANDROID_NATIVE_BUFFER_MAGIC || |
| 346 | buf->common.version != sizeof(*buf)) { |
| 347 | _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR"); |
| 348 | return NULL; |
| 349 | } |
| 350 | |
| 351 | name = get_native_buffer_name(buf); |
| 352 | if (!name) { |
| 353 | _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR"); |
| 354 | return NULL; |
| 355 | } |
| 356 | |
| 357 | /* see the table in droid_add_configs_for_visuals */ |
| 358 | switch (buf->format) { |
| 359 | case HAL_PIXEL_FORMAT_BGRA_8888: |
| 360 | format = __DRI_IMAGE_FORMAT_ARGB8888; |
| 361 | break; |
| 362 | case HAL_PIXEL_FORMAT_RGB_565: |
| 363 | format = __DRI_IMAGE_FORMAT_RGB565; |
| 364 | break; |
| 365 | case HAL_PIXEL_FORMAT_RGBA_8888: |
Chia-I Wu | 48eb1fe | 2011-08-21 21:34:10 +0800 | [diff] [blame] | 366 | format = __DRI_IMAGE_FORMAT_ABGR8888; |
| 367 | break; |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 368 | case HAL_PIXEL_FORMAT_RGBX_8888: |
Sean V Kelley | 81f95ce | 2012-04-24 07:49:09 -0700 | [diff] [blame] | 369 | format = __DRI_IMAGE_FORMAT_XBGR8888; |
| 370 | break; |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 371 | case HAL_PIXEL_FORMAT_RGB_888: |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 372 | /* unsupported */ |
| 373 | default: |
| 374 | _eglLog(_EGL_WARNING, "unsupported native buffer format 0x%x", buf->format); |
| 375 | return NULL; |
| 376 | break; |
| 377 | } |
| 378 | |
| 379 | dri2_img = calloc(1, sizeof(*dri2_img)); |
| 380 | if (!dri2_img) { |
| 381 | _eglError(EGL_BAD_ALLOC, "droid_create_image_mesa_drm"); |
| 382 | return NULL; |
| 383 | } |
| 384 | |
| 385 | if (!_eglInitImage(&dri2_img->base, disp)) { |
| 386 | free(dri2_img); |
| 387 | return NULL; |
| 388 | } |
| 389 | |
| 390 | dri2_img->dri_image = |
| 391 | dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen, |
| 392 | buf->width, |
| 393 | buf->height, |
| 394 | format, |
| 395 | name, |
| 396 | buf->stride, |
| 397 | dri2_img); |
| 398 | if (!dri2_img->dri_image) { |
| 399 | free(dri2_img); |
| 400 | _eglError(EGL_BAD_ALLOC, "droid_create_image_mesa_drm"); |
| 401 | return NULL; |
| 402 | } |
| 403 | |
| 404 | return &dri2_img->base; |
| 405 | } |
| 406 | |
| 407 | static _EGLImage * |
| 408 | droid_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp, |
| 409 | _EGLContext *ctx, EGLenum target, |
| 410 | EGLClientBuffer buffer, const EGLint *attr_list) |
| 411 | { |
| 412 | switch (target) { |
| 413 | case EGL_NATIVE_BUFFER_ANDROID: |
Chad Versace | 2878f46 | 2013-05-06 07:41:11 -0700 | [diff] [blame] | 414 | return dri2_create_image_android_native_buffer(disp, ctx, |
Chia-I Wu | 75cc24c | 2011-11-25 11:59:02 +0800 | [diff] [blame] | 415 | (struct ANativeWindowBuffer *) buffer); |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 416 | default: |
| 417 | return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list); |
| 418 | } |
| 419 | } |
| 420 | |
| 421 | static void |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 422 | droid_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) |
| 423 | { |
| 424 | } |
| 425 | |
Chia-I Wu | 384f228 | 2011-08-26 23:49:04 +0800 | [diff] [blame] | 426 | static int |
| 427 | droid_get_buffers_parse_attachments(struct dri2_egl_surface *dri2_surf, |
| 428 | unsigned int *attachments, int count) |
| 429 | { |
| 430 | int num_buffers = 0, i; |
| 431 | |
| 432 | /* fill dri2_surf->buffers */ |
| 433 | for (i = 0; i < count * 2; i += 2) { |
| 434 | __DRIbuffer *buf, *local; |
| 435 | |
| 436 | assert(num_buffers < ARRAY_SIZE(dri2_surf->buffers)); |
| 437 | buf = &dri2_surf->buffers[num_buffers]; |
| 438 | |
| 439 | switch (attachments[i]) { |
| 440 | case __DRI_BUFFER_BACK_LEFT: |
Chia-I Wu | c8e18f8 | 2011-08-26 22:09:56 +0800 | [diff] [blame] | 441 | if (dri2_surf->base.Type == EGL_WINDOW_BIT) { |
| 442 | buf->attachment = attachments[i]; |
| 443 | buf->name = get_native_buffer_name(dri2_surf->buffer); |
| 444 | buf->cpp = get_format_bpp(dri2_surf->buffer->format); |
| 445 | buf->pitch = dri2_surf->buffer->stride * buf->cpp; |
| 446 | buf->flags = 0; |
Chia-I Wu | 384f228 | 2011-08-26 23:49:04 +0800 | [diff] [blame] | 447 | |
Chia-I Wu | c8e18f8 | 2011-08-26 22:09:56 +0800 | [diff] [blame] | 448 | if (buf->name) |
| 449 | num_buffers++; |
Chia-I Wu | 93d5963 | 2011-08-27 00:00:18 +0800 | [diff] [blame] | 450 | |
| 451 | break; |
Chia-I Wu | c8e18f8 | 2011-08-26 22:09:56 +0800 | [diff] [blame] | 452 | } |
Chia-I Wu | 93d5963 | 2011-08-27 00:00:18 +0800 | [diff] [blame] | 453 | /* fall through for pbuffers */ |
Chia-I Wu | 384f228 | 2011-08-26 23:49:04 +0800 | [diff] [blame] | 454 | case __DRI_BUFFER_DEPTH: |
| 455 | case __DRI_BUFFER_STENCIL: |
| 456 | case __DRI_BUFFER_ACCUM: |
| 457 | case __DRI_BUFFER_DEPTH_STENCIL: |
| 458 | case __DRI_BUFFER_HIZ: |
| 459 | local = droid_alloc_local_buffer(dri2_surf, |
| 460 | attachments[i], attachments[i + 1]); |
| 461 | |
| 462 | if (local) { |
| 463 | *buf = *local; |
| 464 | num_buffers++; |
| 465 | } |
| 466 | break; |
| 467 | case __DRI_BUFFER_FRONT_LEFT: |
| 468 | case __DRI_BUFFER_FRONT_RIGHT: |
| 469 | case __DRI_BUFFER_FAKE_FRONT_LEFT: |
| 470 | case __DRI_BUFFER_FAKE_FRONT_RIGHT: |
| 471 | case __DRI_BUFFER_BACK_RIGHT: |
| 472 | default: |
| 473 | /* no front or right buffers */ |
| 474 | break; |
| 475 | } |
| 476 | } |
| 477 | |
| 478 | return num_buffers; |
| 479 | } |
| 480 | |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 481 | static __DRIbuffer * |
| 482 | droid_get_buffers_with_format(__DRIdrawable * driDrawable, |
| 483 | int *width, int *height, |
| 484 | unsigned int *attachments, int count, |
| 485 | int *out_count, void *loaderPrivate) |
| 486 | { |
| 487 | struct dri2_egl_surface *dri2_surf = loaderPrivate; |
| 488 | struct dri2_egl_display *dri2_dpy = |
| 489 | dri2_egl_display(dri2_surf->base.Resource.Display); |
| 490 | int i; |
| 491 | |
Chia-I Wu | c8e18f8 | 2011-08-26 22:09:56 +0800 | [diff] [blame] | 492 | if (dri2_surf->base.Type == EGL_WINDOW_BIT) { |
| 493 | /* try to dequeue the next back buffer */ |
| 494 | if (!dri2_surf->buffer && !droid_window_dequeue_buffer(dri2_surf)) |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 495 | return NULL; |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 496 | |
Chia-I Wu | c8e18f8 | 2011-08-26 22:09:56 +0800 | [diff] [blame] | 497 | /* free outdated buffers and update the surface size */ |
| 498 | if (dri2_surf->base.Width != dri2_surf->buffer->width || |
| 499 | dri2_surf->base.Height != dri2_surf->buffer->height) { |
| 500 | droid_free_local_buffers(dri2_surf); |
| 501 | dri2_surf->base.Width = dri2_surf->buffer->width; |
| 502 | dri2_surf->base.Height = dri2_surf->buffer->height; |
| 503 | } |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 504 | } |
| 505 | |
Chia-I Wu | 384f228 | 2011-08-26 23:49:04 +0800 | [diff] [blame] | 506 | dri2_surf->buffer_count = |
| 507 | droid_get_buffers_parse_attachments(dri2_surf, attachments, count); |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 508 | |
| 509 | if (width) |
| 510 | *width = dri2_surf->base.Width; |
| 511 | if (height) |
| 512 | *height = dri2_surf->base.Height; |
| 513 | |
| 514 | *out_count = dri2_surf->buffer_count;; |
| 515 | |
| 516 | return dri2_surf->buffers; |
| 517 | } |
| 518 | |
| 519 | static EGLBoolean |
| 520 | droid_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *dpy) |
| 521 | { |
| 522 | struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); |
| 523 | const struct { |
| 524 | int format; |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 525 | unsigned int rgba_masks[4]; |
| 526 | } visuals[] = { |
Kristian Høgsberg | 44e584a | 2013-09-14 23:13:22 -0700 | [diff] [blame] | 527 | { HAL_PIXEL_FORMAT_RGBA_8888, { 0xff, 0xff00, 0xff0000, 0xff000000 } }, |
| 528 | { HAL_PIXEL_FORMAT_RGBX_8888, { 0xff, 0xff00, 0xff0000, 0x0 } }, |
| 529 | { HAL_PIXEL_FORMAT_RGB_888, { 0xff, 0xff00, 0xff0000, 0x0 } }, |
| 530 | { HAL_PIXEL_FORMAT_RGB_565, { 0xf800, 0x7e0, 0x1f, 0x0 } }, |
| 531 | { HAL_PIXEL_FORMAT_BGRA_8888, { 0xff0000, 0xff00, 0xff, 0xff000000 } }, |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 532 | { 0, 0, { 0, 0, 0, 0 } } |
| 533 | }; |
| 534 | int count, i, j; |
| 535 | |
| 536 | count = 0; |
| 537 | for (i = 0; visuals[i].format; i++) { |
| 538 | int format_count = 0; |
| 539 | |
| 540 | for (j = 0; dri2_dpy->driver_configs[j]; j++) { |
Chia-I Wu | 93d5963 | 2011-08-27 00:00:18 +0800 | [diff] [blame] | 541 | const EGLint surface_type = EGL_WINDOW_BIT | EGL_PBUFFER_BIT; |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 542 | struct dri2_egl_config *dri2_conf; |
Tapani Pälli | d58ca43 | 2012-08-13 16:47:52 +0300 | [diff] [blame] | 543 | unsigned int double_buffered = 0; |
| 544 | |
| 545 | dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[j], |
| 546 | __DRI_ATTRIB_DOUBLE_BUFFER, &double_buffered); |
| 547 | |
| 548 | /* support only double buffered configs */ |
| 549 | if (!double_buffered) |
| 550 | continue; |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 551 | |
| 552 | dri2_conf = dri2_add_config(dpy, dri2_dpy->driver_configs[j], |
Kristian Høgsberg | 44e584a | 2013-09-14 23:13:22 -0700 | [diff] [blame] | 553 | count + 1, surface_type, NULL, visuals[i].rgba_masks); |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 554 | if (dri2_conf) { |
| 555 | dri2_conf->base.NativeVisualID = visuals[i].format; |
| 556 | dri2_conf->base.NativeVisualType = visuals[i].format; |
| 557 | count++; |
| 558 | format_count++; |
| 559 | } |
| 560 | } |
| 561 | |
| 562 | if (!format_count) { |
| 563 | _eglLog(_EGL_DEBUG, "No DRI config supports native format 0x%x", |
| 564 | visuals[i].format); |
| 565 | } |
| 566 | } |
| 567 | |
| 568 | /* post-process configs */ |
| 569 | for (i = 0; i < dpy->Configs->Size; i++) { |
| 570 | struct dri2_egl_config *dri2_conf = dri2_egl_config(dpy->Configs->Elements[i]); |
| 571 | |
| 572 | /* there is no front buffer so no OpenGL */ |
| 573 | dri2_conf->base.RenderableType &= ~EGL_OPENGL_BIT; |
| 574 | dri2_conf->base.Conformant &= ~EGL_OPENGL_BIT; |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 575 | } |
| 576 | |
| 577 | return (count != 0); |
| 578 | } |
| 579 | |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 580 | static int |
| 581 | droid_open_device(void) |
| 582 | { |
| 583 | const hw_module_t *mod; |
| 584 | int fd = -1, err; |
| 585 | |
| 586 | err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mod); |
| 587 | if (!err) { |
| 588 | const gralloc_module_t *gr = (gralloc_module_t *) mod; |
| 589 | |
| 590 | err = -EINVAL; |
| 591 | if (gr->perform) |
| 592 | err = gr->perform(gr, GRALLOC_MODULE_PERFORM_GET_DRM_FD, &fd); |
| 593 | } |
| 594 | if (err || fd < 0) { |
| 595 | _eglLog(_EGL_WARNING, "fail to get drm fd"); |
| 596 | fd = -1; |
| 597 | } |
| 598 | |
| 599 | return (fd >= 0) ? dup(fd) : -1; |
| 600 | } |
| 601 | |
Tapani Pälli | 29d394b | 2012-08-13 09:03:06 +0300 | [diff] [blame] | 602 | /* support versions < JellyBean */ |
| 603 | #ifndef ALOGW |
| 604 | #define ALOGW LOGW |
| 605 | #endif |
| 606 | #ifndef ALOGD |
| 607 | #define ALOGD LOGD |
| 608 | #endif |
| 609 | #ifndef ALOGI |
| 610 | #define ALOGI LOGI |
| 611 | #endif |
| 612 | |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 613 | static void |
| 614 | droid_log(EGLint level, const char *msg) |
| 615 | { |
| 616 | switch (level) { |
| 617 | case _EGL_DEBUG: |
Tapani Pälli | 29d394b | 2012-08-13 09:03:06 +0300 | [diff] [blame] | 618 | ALOGD("%s", msg); |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 619 | break; |
| 620 | case _EGL_INFO: |
Tapani Pälli | 29d394b | 2012-08-13 09:03:06 +0300 | [diff] [blame] | 621 | ALOGI("%s", msg); |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 622 | break; |
| 623 | case _EGL_WARNING: |
Tapani Pälli | 29d394b | 2012-08-13 09:03:06 +0300 | [diff] [blame] | 624 | ALOGW("%s", msg); |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 625 | break; |
| 626 | case _EGL_FATAL: |
| 627 | LOG_FATAL("%s", msg); |
| 628 | break; |
| 629 | default: |
| 630 | break; |
| 631 | } |
| 632 | } |
| 633 | |
Chad Versace | 90502b1 | 2014-01-28 11:41:46 -0800 | [diff] [blame] | 634 | static struct dri2_egl_display_vtbl droid_display_vtbl = { |
| 635 | .authenticate = NULL, |
Chad Versace | 0a0c881 | 2014-01-28 16:39:09 -0800 | [diff] [blame] | 636 | .create_window_surface = droid_create_window_surface, |
Adrian Negreanu | 6980cae | 2014-06-06 12:16:10 +0300 | [diff] [blame] | 637 | .create_pixmap_surface = dri2_fallback_create_pixmap_surface, |
Chad Versace | bf20076 | 2014-01-28 17:03:03 -0800 | [diff] [blame] | 638 | .create_pbuffer_surface = droid_create_pbuffer_surface, |
Chad Versace | 958dd80 | 2014-01-28 17:03:03 -0800 | [diff] [blame] | 639 | .destroy_surface = droid_destroy_surface, |
Chad Versace | eef68a9 | 2014-01-28 17:03:03 -0800 | [diff] [blame] | 640 | .create_image = droid_create_image_khr, |
Chad Versace | 8b9298a | 2014-01-28 12:34:19 -0800 | [diff] [blame] | 641 | .swap_interval = dri2_fallback_swap_interval, |
Chad Versace | ad173bc | 2014-01-28 16:21:21 -0800 | [diff] [blame] | 642 | .swap_buffers = droid_swap_buffers, |
Chad Versace | d03948a | 2014-01-28 16:26:44 -0800 | [diff] [blame] | 643 | .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage, |
Chad Versace | 75d398e | 2014-01-28 17:03:03 -0800 | [diff] [blame] | 644 | .swap_buffers_region = dri2_fallback_swap_buffers_region, |
Chad Versace | 688a0e8 | 2014-01-28 17:03:03 -0800 | [diff] [blame] | 645 | .post_sub_buffer = dri2_fallback_post_sub_buffer, |
Chad Versace | bc2cbc0 | 2014-01-28 17:03:03 -0800 | [diff] [blame] | 646 | .copy_buffers = dri2_fallback_copy_buffers, |
Chad Versace | 3fdfbd2 | 2014-01-28 17:03:03 -0800 | [diff] [blame] | 647 | .query_buffer_age = dri2_fallback_query_buffer_age, |
Chad Versace | eadd5e0 | 2014-01-28 17:03:03 -0800 | [diff] [blame] | 648 | .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image, |
Sarah Sharp | c524f3e | 2014-05-06 12:10:57 -0700 | [diff] [blame] | 649 | .get_sync_values = dri2_fallback_get_sync_values, |
Chad Versace | 90502b1 | 2014-01-28 11:41:46 -0800 | [diff] [blame] | 650 | }; |
| 651 | |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 652 | EGLBoolean |
| 653 | dri2_initialize_android(_EGLDriver *drv, _EGLDisplay *dpy) |
| 654 | { |
| 655 | struct dri2_egl_display *dri2_dpy; |
| 656 | const char *err; |
| 657 | |
| 658 | _eglSetLogProc(droid_log); |
| 659 | |
Emil Velikov | 8d4357b | 2014-01-11 04:52:48 +0000 | [diff] [blame] | 660 | loader_set_logger(_eglLog); |
| 661 | |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 662 | dri2_dpy = calloc(1, sizeof(*dri2_dpy)); |
| 663 | if (!dri2_dpy) |
| 664 | return _eglError(EGL_BAD_ALLOC, "eglInitialize"); |
| 665 | |
| 666 | dpy->DriverData = (void *) dri2_dpy; |
| 667 | |
| 668 | dri2_dpy->fd = droid_open_device(); |
| 669 | if (dri2_dpy->fd < 0) { |
| 670 | err = "DRI2: failed to open device"; |
| 671 | goto cleanup_display; |
| 672 | } |
| 673 | |
Emil Velikov | 8d4357b | 2014-01-11 04:52:48 +0000 | [diff] [blame] | 674 | dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd, 0); |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 675 | if (dri2_dpy->driver_name == NULL) { |
| 676 | err = "DRI2: failed to get driver name"; |
| 677 | goto cleanup_device; |
| 678 | } |
| 679 | |
| 680 | if (!dri2_load_driver(dpy)) { |
| 681 | err = "DRI2: failed to load driver"; |
Emil Velikov | 165eecf | 2014-01-25 15:56:59 +0000 | [diff] [blame] | 682 | goto cleanup_driver_name; |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 683 | } |
| 684 | |
| 685 | dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER; |
| 686 | dri2_dpy->dri2_loader_extension.base.version = 3; |
| 687 | dri2_dpy->dri2_loader_extension.getBuffers = NULL; |
| 688 | dri2_dpy->dri2_loader_extension.flushFrontBuffer = droid_flush_front_buffer; |
| 689 | dri2_dpy->dri2_loader_extension.getBuffersWithFormat = |
| 690 | droid_get_buffers_with_format; |
| 691 | |
| 692 | dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base; |
| 693 | dri2_dpy->extensions[1] = &image_lookup_extension.base; |
| 694 | dri2_dpy->extensions[2] = &use_invalidate.base; |
| 695 | dri2_dpy->extensions[3] = NULL; |
| 696 | |
| 697 | if (!dri2_create_screen(dpy)) { |
| 698 | err = "DRI2: failed to create screen"; |
| 699 | goto cleanup_driver; |
| 700 | } |
| 701 | |
| 702 | if (!droid_add_configs_for_visuals(drv, dpy)) { |
| 703 | err = "DRI2: failed to add configs"; |
| 704 | goto cleanup_screen; |
| 705 | } |
| 706 | |
| 707 | dpy->Extensions.ANDROID_image_native_buffer = EGL_TRUE; |
| 708 | dpy->Extensions.KHR_image_base = EGL_TRUE; |
| 709 | |
| 710 | /* we're supporting EGL 1.4 */ |
| 711 | dpy->VersionMajor = 1; |
| 712 | dpy->VersionMinor = 4; |
| 713 | |
Chad Versace | 90502b1 | 2014-01-28 11:41:46 -0800 | [diff] [blame] | 714 | /* Fill vtbl last to prevent accidentally calling virtual function during |
| 715 | * initialization. |
| 716 | */ |
| 717 | dri2_dpy->vtbl = &droid_display_vtbl; |
| 718 | |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 719 | return EGL_TRUE; |
| 720 | |
| 721 | cleanup_screen: |
| 722 | dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen); |
| 723 | cleanup_driver: |
| 724 | dlclose(dri2_dpy->driver); |
Emil Velikov | 165eecf | 2014-01-25 15:56:59 +0000 | [diff] [blame] | 725 | cleanup_driver_name: |
| 726 | free(dri2_dpy->driver_name); |
Chia-I Wu | 9779f6f | 2011-08-05 14:39:18 +0900 | [diff] [blame] | 727 | cleanup_device: |
| 728 | close(dri2_dpy->fd); |
| 729 | cleanup_display: |
| 730 | free(dri2_dpy); |
| 731 | |
| 732 | return _eglError(EGL_NOT_INITIALIZED, err); |
| 733 | } |