egl_g3d_image.c revision 4f6faf65d124bd690c4526f4c8e95de4d041601f
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.8 4 * 5 * Copyright (C) 2010 LunarG Inc. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 * 25 * Authors: 26 * Chia-I Wu <olv@lunarg.com> 27 */ 28 29#include "pipe/p_screen.h" 30#include "util/u_memory.h" 31#include "util/u_rect.h" 32#include "util/u_inlines.h" 33#include "eglcurrent.h" 34#include "egllog.h" 35 36#include "native.h" 37#include "egl_g3d.h" 38#include "egl_g3d_api.h" 39#include "egl_g3d_image.h" 40 41/* move this to native display? */ 42#include "state_tracker/drm_driver.h" 43 44/** 45 * Reference and return the front left buffer of the native pixmap. 46 */ 47static struct pipe_resource * 48egl_g3d_reference_native_pixmap(_EGLDisplay *dpy, EGLNativePixmapType pix) 49{ 50 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 51 struct egl_g3d_config *gconf; 52 struct native_surface *nsurf; 53 struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS]; 54 enum native_attachment natt; 55 56 gconf = egl_g3d_config(egl_g3d_find_pixmap_config(dpy, pix)); 57 if (!gconf) 58 return NULL; 59 60 nsurf = gdpy->native->create_pixmap_surface(gdpy->native, 61 pix, gconf->native); 62 if (!nsurf) 63 return NULL; 64 65 natt = NATIVE_ATTACHMENT_FRONT_LEFT; 66 if (!nsurf->validate(nsurf, 1 << natt, NULL, textures, NULL, NULL)) 67 textures[natt] = NULL; 68 69 nsurf->destroy(nsurf); 70 71 return textures[natt]; 72} 73 74#ifdef EGL_MESA_drm_image 75 76static struct pipe_resource * 77egl_g3d_create_drm_buffer(_EGLDisplay *dpy, const EGLint *attribs) 78{ 79 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 80 struct pipe_screen *screen = gdpy->native->screen; 81 struct pipe_resource templ; 82 EGLint width = 0, height = 0, format = 0, use = 0; 83 EGLint valid_use; 84 EGLint i, err = EGL_SUCCESS; 85 86 for (i = 0; attribs[i] != EGL_NONE; i++) { 87 EGLint attr = attribs[i++]; 88 EGLint val = attribs[i]; 89 90 switch (attr) { 91 case EGL_WIDTH: 92 width = val; 93 break; 94 case EGL_HEIGHT: 95 height = val; 96 break; 97 case EGL_DRM_BUFFER_FORMAT_MESA: 98 format = val; 99 break; 100 case EGL_DRM_BUFFER_USE_MESA: 101 use = val; 102 break; 103 default: 104 err = EGL_BAD_ATTRIBUTE; 105 break; 106 } 107 108 if (err != EGL_SUCCESS) { 109 _eglLog(_EGL_DEBUG, "bad image attribute 0x%04x", attr); 110 return NULL; 111 } 112 } 113 114 if (width <= 0 || height <= 0) { 115 _eglLog(_EGL_DEBUG, "bad width or height (%dx%d)", width, height); 116 return NULL; 117 } 118 119 switch (format) { 120 case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: 121 format = PIPE_FORMAT_B8G8R8A8_UNORM; 122 break; 123 default: 124 _eglLog(_EGL_DEBUG, "bad image format value 0x%04x", format); 125 return NULL; 126 break; 127 } 128 129 valid_use = EGL_DRM_BUFFER_USE_SCANOUT_MESA | 130 EGL_DRM_BUFFER_USE_SHARE_MESA; 131 if (use & ~valid_use) { 132 _eglLog(_EGL_DEBUG, "bad image use bit 0x%04x", use); 133 return NULL; 134 } 135 136 memset(&templ, 0, sizeof(templ)); 137 templ.target = PIPE_TEXTURE_2D; 138 templ.format = format; 139 templ.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; 140 templ.width0 = width; 141 templ.height0 = height; 142 templ.depth0 = 1; 143 144 /* 145 * XXX fix apps (e.g. wayland) and pipe drivers (e.g. i915) and remove the 146 * size check 147 */ 148 if ((use & EGL_DRM_BUFFER_USE_SCANOUT_MESA) && 149 width >= 640 && height >= 480) 150 templ.bind |= PIPE_BIND_SCANOUT; 151 if (use & EGL_DRM_BUFFER_USE_SHARE_MESA) 152 templ.bind |= PIPE_BIND_SHARED; 153 154 return screen->resource_create(screen, &templ); 155} 156 157static struct pipe_resource * 158egl_g3d_reference_drm_buffer(_EGLDisplay *dpy, EGLint name, 159 const EGLint *attribs) 160{ 161 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 162 struct pipe_screen *screen = gdpy->native->screen; 163 struct pipe_resource templ; 164 struct winsys_handle wsh; 165 EGLint width = 0, height = 0, format = 0, stride = 0; 166 EGLint i, err = EGL_SUCCESS; 167 168 /* winsys_handle is in theory platform-specific */ 169 if (dpy->Platform != _EGL_PLATFORM_DRM) 170 return NULL; 171 172 for (i = 0; attribs[i] != EGL_NONE; i++) { 173 EGLint attr = attribs[i++]; 174 EGLint val = attribs[i]; 175 176 switch (attr) { 177 case EGL_WIDTH: 178 width = val; 179 break; 180 case EGL_HEIGHT: 181 height = val; 182 break; 183 case EGL_DRM_BUFFER_FORMAT_MESA: 184 format = val; 185 break; 186 case EGL_DRM_BUFFER_STRIDE_MESA: 187 stride = val; 188 break; 189 default: 190 err = EGL_BAD_ATTRIBUTE; 191 break; 192 } 193 194 if (err != EGL_SUCCESS) { 195 _eglLog(_EGL_DEBUG, "bad image attribute 0x%04x", attr); 196 return NULL; 197 } 198 } 199 200 if (width <= 0 || height <= 0 || stride <= 0) { 201 _eglLog(_EGL_DEBUG, "bad width, height, or stride (%dx%dx%d)", 202 width, height, stride); 203 return NULL; 204 } 205 206 switch (format) { 207 case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: 208 format = PIPE_FORMAT_B8G8R8A8_UNORM; 209 break; 210 default: 211 _eglLog(_EGL_DEBUG, "bad image format value 0x%04x", format); 212 return NULL; 213 break; 214 } 215 216 memset(&templ, 0, sizeof(templ)); 217 templ.target = PIPE_TEXTURE_2D; 218 templ.format = format; 219 templ.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; 220 templ.width0 = width; 221 templ.height0 = height; 222 templ.depth0 = 1; 223 224 memset(&wsh, 0, sizeof(wsh)); 225 wsh.handle = (unsigned) name; 226 wsh.stride = stride; 227 228 return screen->resource_from_handle(screen, &templ, &wsh); 229} 230 231#endif /* EGL_MESA_drm_image */ 232 233_EGLImage * 234egl_g3d_create_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx, 235 EGLenum target, EGLClientBuffer buffer, 236 const EGLint *attribs) 237{ 238 struct pipe_resource *ptex; 239 struct egl_g3d_image *gimg; 240 unsigned face = 0, level = 0, zslice = 0; 241 242 gimg = CALLOC_STRUCT(egl_g3d_image); 243 if (!gimg) { 244 _eglError(EGL_BAD_ALLOC, "eglCreateEGLImageKHR"); 245 return NULL; 246 } 247 248 if (!_eglInitImage(&gimg->base, dpy, attribs)) { 249 FREE(gimg); 250 return NULL; 251 } 252 253 switch (target) { 254 case EGL_NATIVE_PIXMAP_KHR: 255 ptex = egl_g3d_reference_native_pixmap(dpy, 256 (EGLNativePixmapType) buffer); 257 break; 258#ifdef EGL_MESA_drm_image 259 case EGL_DRM_BUFFER_MESA: 260 ptex = egl_g3d_reference_drm_buffer(dpy, (EGLint) buffer, attribs); 261 break; 262#endif 263 default: 264 ptex = NULL; 265 break; 266 } 267 268 if (!ptex) { 269 FREE(gimg); 270 return NULL; 271 } 272 273 if (level > ptex->last_level) { 274 _eglError(EGL_BAD_MATCH, "eglCreateEGLImageKHR"); 275 pipe_resource_reference(&gimg->texture, NULL); 276 FREE(gimg); 277 return NULL; 278 } 279 if (zslice > ptex->depth0) { 280 _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR"); 281 pipe_resource_reference(&gimg->texture, NULL); 282 FREE(gimg); 283 return NULL; 284 } 285 286 /* transfer the ownership to the image */ 287 gimg->texture = ptex; 288 gimg->face = face; 289 gimg->level = level; 290 gimg->zslice = zslice; 291 292 return &gimg->base; 293} 294 295EGLBoolean 296egl_g3d_destroy_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *img) 297{ 298 struct egl_g3d_image *gimg = egl_g3d_image(img); 299 300 pipe_resource_reference(&gimg->texture, NULL); 301 FREE(gimg); 302 303 return EGL_TRUE; 304} 305 306_EGLImage * 307egl_g3d_create_drm_image(_EGLDriver *drv, _EGLDisplay *dpy, 308 const EGLint *attribs) 309{ 310 struct egl_g3d_image *gimg; 311 struct pipe_resource *ptex; 312 313 gimg = CALLOC_STRUCT(egl_g3d_image); 314 if (!gimg) { 315 _eglError(EGL_BAD_ALLOC, "eglCreateDRMImageKHR"); 316 return NULL; 317 } 318 319 if (!_eglInitImage(&gimg->base, dpy, attribs)) { 320 FREE(gimg); 321 return NULL; 322 } 323 324#ifdef EGL_MESA_drm_image 325 ptex = egl_g3d_create_drm_buffer(dpy, attribs); 326#else 327 ptex = NULL; 328#endif 329 if (!ptex) { 330 FREE(gimg); 331 return NULL; 332 } 333 334 /* transfer the ownership to the image */ 335 gimg->texture = ptex; 336 gimg->face = 0; 337 gimg->level = 0; 338 gimg->zslice = 0; 339 340 return &gimg->base; 341} 342 343EGLBoolean 344egl_g3d_export_drm_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *img, 345 EGLint *name, EGLint *handle, EGLint *stride) 346{ 347 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 348 struct egl_g3d_image *gimg = egl_g3d_image(img); 349 struct pipe_screen *screen = gdpy->native->screen; 350 struct winsys_handle wsh; 351 352 /* winsys_handle is in theory platform-specific */ 353 if (dpy->Platform != _EGL_PLATFORM_DRM) 354 return EGL_FALSE; 355 356 /* get shared handle */ 357 if (name) { 358 memset(&handle, 0, sizeof(handle)); 359 wsh.type = DRM_API_HANDLE_TYPE_SHARED; 360 if (!screen->resource_get_handle(screen, gimg->texture, &wsh)) { 361 return EGL_FALSE; 362 } 363 364 *name = wsh.handle; 365 } 366 367 /* get KMS handle */ 368 if (handle || stride) { 369 memset(&wsh, 0, sizeof(wsh)); 370 wsh.type = DRM_API_HANDLE_TYPE_KMS; 371 if (!screen->resource_get_handle(screen, gimg->texture, &wsh)) 372 return EGL_FALSE; 373 374 if (handle) 375 *handle = wsh.handle; 376 if (stride) 377 *stride = wsh.stride; 378 } 379 380 return EGL_TRUE; 381} 382