1 /* 2 * Mesa 3-D graphics library 3 * Version: 7.9 4 * 5 * Copyright (C) 2010 LunarG Inc. 6 * Copyright (C) 2011 VMware Inc. All rights reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included 16 * in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 * DEALINGS IN THE SOFTWARE. 25 * 26 * Authors: 27 * Chia-I Wu <olv (at) lunarg.com> 28 * Thomas Hellstrom <thellstrom (at) vmware.com> 29 */ 30 31 #include "util/u_inlines.h" 32 #include "util/u_memory.h" 33 #include "pipe/p_screen.h" 34 #include "pipe/p_context.h" 35 #include "pipe/p_state.h" 36 37 #include "native_helper.h" 38 39 /** 40 * Number of swap fences and mask 41 */ 42 43 #define EGL_SWAP_FENCES_MAX 4 44 #define EGL_SWAP_FENCES_MASK 3 45 #define EGL_SWAP_FENCES_DEFAULT 1 46 47 struct resource_surface { 48 struct pipe_screen *screen; 49 enum pipe_format format; 50 uint bind; 51 52 struct pipe_resource *resources[NUM_NATIVE_ATTACHMENTS]; 53 uint resource_mask; 54 uint width, height; 55 56 /** 57 * Swap fences. 58 */ 59 struct pipe_fence_handle *swap_fences[EGL_SWAP_FENCES_MAX]; 60 unsigned int cur_fences; 61 unsigned int head; 62 unsigned int tail; 63 unsigned int desired_fences; 64 }; 65 66 struct resource_surface * 67 resource_surface_create(struct pipe_screen *screen, 68 enum pipe_format format, uint bind) 69 { 70 struct resource_surface *rsurf = CALLOC_STRUCT(resource_surface); 71 char *swap_fences = getenv("EGL_THROTTLE_FENCES"); 72 73 if (rsurf) { 74 rsurf->screen = screen; 75 rsurf->format = format; 76 rsurf->bind = bind; 77 rsurf->desired_fences = (swap_fences) ? atoi(swap_fences) : 78 EGL_SWAP_FENCES_DEFAULT; 79 if (rsurf->desired_fences > EGL_SWAP_FENCES_MAX) 80 rsurf->desired_fences = EGL_SWAP_FENCES_MAX; 81 } 82 83 return rsurf; 84 } 85 86 static void 87 resource_surface_free_resources(struct resource_surface *rsurf) 88 { 89 if (rsurf->resource_mask) { 90 int i; 91 92 for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) { 93 if (rsurf->resources[i]) 94 pipe_resource_reference(&rsurf->resources[i], NULL); 95 } 96 rsurf->resource_mask = 0x0; 97 } 98 } 99 100 void 101 resource_surface_destroy(struct resource_surface *rsurf) 102 { 103 resource_surface_free_resources(rsurf); 104 FREE(rsurf); 105 } 106 107 boolean 108 resource_surface_set_size(struct resource_surface *rsurf, 109 uint width, uint height) 110 { 111 boolean changed = FALSE; 112 113 if (rsurf->width != width || rsurf->height != height) { 114 resource_surface_free_resources(rsurf); 115 rsurf->width = width; 116 rsurf->height = height; 117 changed = TRUE; 118 } 119 120 return changed; 121 } 122 123 void 124 resource_surface_get_size(struct resource_surface *rsurf, 125 uint *width, uint *height) 126 { 127 if (width) 128 *width = rsurf->width; 129 if (height) 130 *height = rsurf->height; 131 } 132 133 boolean 134 resource_surface_add_resources(struct resource_surface *rsurf, 135 uint resource_mask) 136 { 137 struct pipe_resource templ; 138 int i; 139 140 resource_mask &= ~rsurf->resource_mask; 141 if (!resource_mask) 142 return TRUE; 143 144 if (!rsurf->width || !rsurf->height) 145 return FALSE; 146 147 memset(&templ, 0, sizeof(templ)); 148 templ.target = PIPE_TEXTURE_2D; 149 templ.format = rsurf->format; 150 templ.bind = rsurf->bind; 151 templ.width0 = rsurf->width; 152 templ.height0 = rsurf->height; 153 templ.depth0 = 1; 154 templ.array_size = 1; 155 156 for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) { 157 if (resource_mask & (1 <<i)) { 158 assert(!rsurf->resources[i]); 159 160 rsurf->resources[i] = 161 rsurf->screen->resource_create(rsurf->screen, &templ); 162 if (rsurf->resources[i]) 163 rsurf->resource_mask |= 1 << i; 164 } 165 } 166 167 return ((rsurf->resource_mask & resource_mask) == resource_mask); 168 } 169 170 void 171 resource_surface_import_resource(struct resource_surface *rsurf, 172 enum native_attachment which, 173 struct pipe_resource *pres) 174 { 175 pipe_resource_reference(&rsurf->resources[which], pres); 176 rsurf->resource_mask |= 1 << which; 177 } 178 179 void 180 resource_surface_get_resources(struct resource_surface *rsurf, 181 struct pipe_resource **resources, 182 uint resource_mask) 183 { 184 int i; 185 186 for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) { 187 if (resource_mask & (1 << i)) { 188 resources[i] = NULL; 189 pipe_resource_reference(&resources[i], rsurf->resources[i]); 190 } 191 } 192 } 193 194 struct pipe_resource * 195 resource_surface_get_single_resource(struct resource_surface *rsurf, 196 enum native_attachment which) 197 { 198 struct pipe_resource *pres = NULL; 199 pipe_resource_reference(&pres, rsurf->resources[which]); 200 return pres; 201 } 202 203 static INLINE void 204 pointer_swap(const void **p1, const void **p2) 205 { 206 const void *tmp = *p1; 207 *p1 = *p2; 208 *p2 = tmp; 209 } 210 211 void 212 resource_surface_swap_buffers(struct resource_surface *rsurf, 213 enum native_attachment buf1, 214 enum native_attachment buf2, 215 boolean only_if_exist) 216 { 217 const uint buf1_bit = 1 << buf1; 218 const uint buf2_bit = 1 << buf2; 219 uint mask; 220 221 if (only_if_exist && !(rsurf->resources[buf1] && rsurf->resources[buf2])) 222 return; 223 224 pointer_swap((const void **) &rsurf->resources[buf1], 225 (const void **) &rsurf->resources[buf2]); 226 227 /* swap mask bits */ 228 mask = rsurf->resource_mask & ~(buf1_bit | buf2_bit); 229 if (rsurf->resource_mask & buf1_bit) 230 mask |= buf2_bit; 231 if (rsurf->resource_mask & buf2_bit) 232 mask |= buf1_bit; 233 234 rsurf->resource_mask = mask; 235 } 236 237 boolean 238 resource_surface_present(struct resource_surface *rsurf, 239 enum native_attachment which, 240 void *winsys_drawable_handle) 241 { 242 struct pipe_resource *pres = rsurf->resources[which]; 243 244 if (!pres) 245 return TRUE; 246 247 rsurf->screen->flush_frontbuffer(rsurf->screen, 248 pres, 0, 0, winsys_drawable_handle); 249 250 return TRUE; 251 } 252 253 /** 254 * Schedule a copy swap from the back to the front buffer using the 255 * native display's copy context. 256 */ 257 boolean 258 resource_surface_copy_swap(struct resource_surface *rsurf, 259 struct native_display *ndpy) 260 { 261 struct pipe_resource *ftex; 262 struct pipe_resource *btex; 263 struct pipe_context *pipe; 264 struct pipe_box src_box; 265 boolean ret = FALSE; 266 267 pipe = ndpy_get_copy_context(ndpy); 268 if (!pipe) 269 return FALSE; 270 271 ftex = resource_surface_get_single_resource(rsurf, 272 NATIVE_ATTACHMENT_FRONT_LEFT); 273 if (!ftex) 274 goto out_no_ftex; 275 btex = resource_surface_get_single_resource(rsurf, 276 NATIVE_ATTACHMENT_BACK_LEFT); 277 if (!btex) 278 goto out_no_btex; 279 280 u_box_origin_2d(ftex->width0, ftex->height0, &src_box); 281 pipe->resource_copy_region(pipe, ftex, 0, 0, 0, 0, 282 btex, 0, &src_box); 283 ret = TRUE; 284 285 out_no_btex: 286 pipe_resource_reference(&btex, NULL); 287 out_no_ftex: 288 pipe_resource_reference(&ftex, NULL); 289 290 return ret; 291 } 292 293 static struct pipe_fence_handle * 294 swap_fences_pop_front(struct resource_surface *rsurf) 295 { 296 struct pipe_screen *screen = rsurf->screen; 297 struct pipe_fence_handle *fence = NULL; 298 299 if (rsurf->desired_fences == 0) 300 return NULL; 301 302 if (rsurf->cur_fences >= rsurf->desired_fences) { 303 screen->fence_reference(screen, &fence, rsurf->swap_fences[rsurf->tail]); 304 screen->fence_reference(screen, &rsurf->swap_fences[rsurf->tail++], NULL); 305 rsurf->tail &= EGL_SWAP_FENCES_MASK; 306 --rsurf->cur_fences; 307 } 308 return fence; 309 } 310 311 static void 312 swap_fences_push_back(struct resource_surface *rsurf, 313 struct pipe_fence_handle *fence) 314 { 315 struct pipe_screen *screen = rsurf->screen; 316 317 if (!fence || rsurf->desired_fences == 0) 318 return; 319 320 while(rsurf->cur_fences == rsurf->desired_fences) 321 swap_fences_pop_front(rsurf); 322 323 rsurf->cur_fences++; 324 screen->fence_reference(screen, &rsurf->swap_fences[rsurf->head++], 325 fence); 326 rsurf->head &= EGL_SWAP_FENCES_MASK; 327 } 328 329 boolean 330 resource_surface_throttle(struct resource_surface *rsurf) 331 { 332 struct pipe_screen *screen = rsurf->screen; 333 struct pipe_fence_handle *fence = swap_fences_pop_front(rsurf); 334 335 if (fence) { 336 (void) screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE); 337 screen->fence_reference(screen, &fence, NULL); 338 return TRUE; 339 } 340 341 return FALSE; 342 } 343 344 boolean 345 resource_surface_flush(struct resource_surface *rsurf, 346 struct native_display *ndpy) 347 { 348 struct pipe_fence_handle *fence = NULL; 349 struct pipe_screen *screen = rsurf->screen; 350 struct pipe_context *pipe= ndpy_get_copy_context(ndpy); 351 352 if (!pipe) 353 return FALSE; 354 355 pipe->flush(pipe, &fence); 356 if (fence == NULL) 357 return FALSE; 358 359 swap_fences_push_back(rsurf, fence); 360 screen->fence_reference(screen, &fence, NULL); 361 362 return TRUE; 363 } 364 365 void 366 resource_surface_wait(struct resource_surface *rsurf) 367 { 368 while (resource_surface_throttle(rsurf)); 369 } 370 371 boolean 372 native_display_copy_to_pixmap(struct native_display *ndpy, 373 EGLNativePixmapType pix, 374 struct pipe_resource *src) 375 { 376 struct pipe_context *pipe; 377 struct native_surface *nsurf; 378 struct pipe_resource *dst; 379 struct pipe_resource *tmp[NUM_NATIVE_ATTACHMENTS]; 380 const enum native_attachment natt = NATIVE_ATTACHMENT_FRONT_LEFT; 381 382 pipe = ndpy_get_copy_context(ndpy); 383 if (!pipe) 384 return FALSE; 385 386 nsurf = ndpy->create_pixmap_surface(ndpy, pix, NULL); 387 if (!nsurf) 388 return FALSE; 389 390 /* get the texutre */ 391 tmp[natt] = NULL; 392 nsurf->validate(nsurf, 1 << natt, NULL, tmp, NULL, NULL); 393 dst = tmp[natt]; 394 395 if (dst && dst->format == src->format) { 396 struct native_present_control ctrl; 397 struct pipe_box src_box; 398 399 u_box_origin_2d(src->width0, src->height0, &src_box); 400 pipe->resource_copy_region(pipe, dst, 0, 0, 0, 0, src, 0, &src_box); 401 pipe->flush(pipe, NULL); 402 403 memset(&ctrl, 0, sizeof(ctrl)); 404 ctrl.natt = natt; 405 nsurf->present(nsurf, &ctrl); 406 } 407 408 if (dst) 409 pipe_resource_reference(&dst, NULL); 410 411 nsurf->destroy(nsurf); 412 413 return TRUE; 414 } 415 416 #include "state_tracker/drm_driver.h" 417 struct pipe_resource * 418 drm_display_import_native_buffer(struct native_display *ndpy, 419 struct native_buffer *nbuf) 420 { 421 struct pipe_screen *screen = ndpy->screen; 422 struct pipe_resource *res = NULL; 423 424 switch (nbuf->type) { 425 case NATIVE_BUFFER_DRM: 426 { 427 struct winsys_handle wsh; 428 429 memset(&wsh, 0, sizeof(wsh)); 430 wsh.handle = nbuf->u.drm.name; 431 wsh.stride = nbuf->u.drm.stride; 432 433 res = screen->resource_from_handle(screen, &nbuf->u.drm.templ, &wsh); 434 } 435 break; 436 default: 437 break; 438 } 439 440 return res; 441 } 442 443 boolean 444 drm_display_export_native_buffer(struct native_display *ndpy, 445 struct pipe_resource *res, 446 struct native_buffer *nbuf) 447 { 448 struct pipe_screen *screen = ndpy->screen; 449 boolean ret = FALSE; 450 451 switch (nbuf->type) { 452 case NATIVE_BUFFER_DRM: 453 { 454 struct winsys_handle wsh; 455 456 if ((nbuf->u.drm.templ.bind & res->bind) != nbuf->u.drm.templ.bind) 457 break; 458 459 memset(&wsh, 0, sizeof(wsh)); 460 wsh.type = DRM_API_HANDLE_TYPE_KMS; 461 if (!screen->resource_get_handle(screen, res, &wsh)) 462 break; 463 464 nbuf->u.drm.handle = wsh.handle; 465 nbuf->u.drm.stride = wsh.stride; 466 467 /* get the name of the GEM object */ 468 if (nbuf->u.drm.templ.bind & PIPE_BIND_SHARED) { 469 memset(&wsh, 0, sizeof(wsh)); 470 wsh.type = DRM_API_HANDLE_TYPE_SHARED; 471 if (!screen->resource_get_handle(screen, res, &wsh)) 472 break; 473 474 nbuf->u.drm.name = wsh.handle; 475 } 476 477 nbuf->u.drm.templ = *res; 478 ret = TRUE; 479 } 480 break; 481 default: 482 break; 483 } 484 485 return ret; 486 } 487