egl_g3d_image.c revision 6102683b191c5306a5ff40978d020393635b7c62
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, _EGLImage *img, 78 const EGLint *attribs) 79{ 80 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 81 struct pipe_screen *screen = gdpy->native->screen; 82 struct pipe_resource templ; 83 _EGLImageAttribs attrs; 84 EGLint format, valid_use; 85 86 if (_eglParseImageAttribList(&attrs, dpy, attribs) != EGL_SUCCESS) 87 return NULL; 88 89 if (attrs.Width <= 0 || attrs.Height <= 0) { 90 _eglLog(_EGL_DEBUG, "bad width or height (%dx%d)", 91 attrs.Width, attrs.Height); 92 return NULL; 93 } 94 95 switch (attrs.DRMBufferFormatMESA) { 96 case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: 97 format = PIPE_FORMAT_B8G8R8A8_UNORM; 98 break; 99 default: 100 _eglLog(_EGL_DEBUG, "bad image format value 0x%04x", 101 attrs.DRMBufferFormatMESA); 102 return NULL; 103 break; 104 } 105 106 valid_use = EGL_DRM_BUFFER_USE_SCANOUT_MESA | 107 EGL_DRM_BUFFER_USE_SHARE_MESA; 108 if (attrs.DRMBufferUseMESA & ~valid_use) { 109 _eglLog(_EGL_DEBUG, "bad image use bit 0x%04x", 110 attrs.DRMBufferUseMESA); 111 return NULL; 112 } 113 114 memset(&templ, 0, sizeof(templ)); 115 templ.target = PIPE_TEXTURE_2D; 116 templ.format = format; 117 templ.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; 118 templ.width0 = attrs.Width; 119 templ.height0 = attrs.Height; 120 templ.depth0 = 1; 121 122 /* 123 * XXX fix apps (e.g. wayland) and pipe drivers (e.g. i915) and remove the 124 * size check 125 */ 126 if ((attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_SCANOUT_MESA) && 127 attrs.Width >= 640 && attrs.Height >= 480) 128 templ.bind |= PIPE_BIND_SCANOUT; 129 if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_SHARE_MESA) 130 templ.bind |= PIPE_BIND_SHARED; 131 132 return screen->resource_create(screen, &templ); 133} 134 135static struct pipe_resource * 136egl_g3d_reference_drm_buffer(_EGLDisplay *dpy, EGLint name, 137 _EGLImage *img, const EGLint *attribs) 138{ 139 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 140 struct pipe_screen *screen = gdpy->native->screen; 141 struct pipe_resource templ; 142 struct winsys_handle wsh; 143 _EGLImageAttribs attrs; 144 EGLint format; 145 146 /* winsys_handle is in theory platform-specific */ 147 if (dpy->Platform != _EGL_PLATFORM_DRM) 148 return NULL; 149 150 if (_eglParseImageAttribList(&attrs, dpy, attribs) != EGL_SUCCESS) 151 return NULL; 152 153 if (attrs.Width <= 0 || attrs.Height <= 0 || 154 attrs.DRMBufferStrideMESA <= 0) { 155 _eglLog(_EGL_DEBUG, "bad width, height, or stride (%dx%dx%d)", 156 attrs.Width, attrs.Height, attrs.DRMBufferStrideMESA); 157 return NULL; 158 } 159 160 switch (attrs.DRMBufferFormatMESA) { 161 case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: 162 format = PIPE_FORMAT_B8G8R8A8_UNORM; 163 break; 164 default: 165 _eglLog(_EGL_DEBUG, "bad image format value 0x%04x", 166 attrs.DRMBufferFormatMESA); 167 return NULL; 168 break; 169 } 170 171 memset(&templ, 0, sizeof(templ)); 172 templ.target = PIPE_TEXTURE_2D; 173 templ.format = format; 174 templ.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; 175 templ.width0 = attrs.Width; 176 templ.height0 = attrs.Height; 177 templ.depth0 = 1; 178 179 memset(&wsh, 0, sizeof(wsh)); 180 wsh.handle = (unsigned) name; 181 wsh.stride = 182 attrs.DRMBufferStrideMESA * util_format_get_blocksize(templ.format); 183 184 return screen->resource_from_handle(screen, &templ, &wsh); 185} 186 187#endif /* EGL_MESA_drm_image */ 188 189_EGLImage * 190egl_g3d_create_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx, 191 EGLenum target, EGLClientBuffer buffer, 192 const EGLint *attribs) 193{ 194 struct pipe_resource *ptex; 195 struct egl_g3d_image *gimg; 196 unsigned face = 0, level = 0, zslice = 0; 197 198 gimg = CALLOC_STRUCT(egl_g3d_image); 199 if (!gimg) { 200 _eglError(EGL_BAD_ALLOC, "eglCreateEGLImageKHR"); 201 return NULL; 202 } 203 204 if (!_eglInitImage(&gimg->base, dpy)) { 205 FREE(gimg); 206 return NULL; 207 } 208 209 switch (target) { 210 case EGL_NATIVE_PIXMAP_KHR: 211 ptex = egl_g3d_reference_native_pixmap(dpy, 212 (EGLNativePixmapType) buffer); 213 break; 214#ifdef EGL_MESA_drm_image 215 case EGL_DRM_BUFFER_MESA: 216 ptex = egl_g3d_reference_drm_buffer(dpy, 217 (EGLint) buffer, &gimg->base, attribs); 218 break; 219#endif 220 default: 221 ptex = NULL; 222 break; 223 } 224 225 if (!ptex) { 226 FREE(gimg); 227 return NULL; 228 } 229 230 if (level > ptex->last_level) { 231 _eglError(EGL_BAD_MATCH, "eglCreateEGLImageKHR"); 232 pipe_resource_reference(&gimg->texture, NULL); 233 FREE(gimg); 234 return NULL; 235 } 236 if (zslice > ptex->depth0) { 237 _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR"); 238 pipe_resource_reference(&gimg->texture, NULL); 239 FREE(gimg); 240 return NULL; 241 } 242 243 /* transfer the ownership to the image */ 244 gimg->texture = ptex; 245 gimg->face = face; 246 gimg->level = level; 247 gimg->zslice = zslice; 248 249 return &gimg->base; 250} 251 252EGLBoolean 253egl_g3d_destroy_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *img) 254{ 255 struct egl_g3d_image *gimg = egl_g3d_image(img); 256 257 pipe_resource_reference(&gimg->texture, NULL); 258 FREE(gimg); 259 260 return EGL_TRUE; 261} 262 263_EGLImage * 264egl_g3d_create_drm_image(_EGLDriver *drv, _EGLDisplay *dpy, 265 const EGLint *attribs) 266{ 267 struct egl_g3d_image *gimg; 268 struct pipe_resource *ptex; 269 270 gimg = CALLOC_STRUCT(egl_g3d_image); 271 if (!gimg) { 272 _eglError(EGL_BAD_ALLOC, "eglCreateDRMImageKHR"); 273 return NULL; 274 } 275 276 if (!_eglInitImage(&gimg->base, dpy)) { 277 FREE(gimg); 278 return NULL; 279 } 280 281#ifdef EGL_MESA_drm_image 282 ptex = egl_g3d_create_drm_buffer(dpy, &gimg->base, attribs); 283#else 284 ptex = NULL; 285#endif 286 if (!ptex) { 287 FREE(gimg); 288 return NULL; 289 } 290 291 /* transfer the ownership to the image */ 292 gimg->texture = ptex; 293 gimg->face = 0; 294 gimg->level = 0; 295 gimg->zslice = 0; 296 297 return &gimg->base; 298} 299 300EGLBoolean 301egl_g3d_export_drm_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *img, 302 EGLint *name, EGLint *handle, EGLint *stride) 303{ 304 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 305 struct egl_g3d_image *gimg = egl_g3d_image(img); 306 struct pipe_screen *screen = gdpy->native->screen; 307 struct winsys_handle wsh; 308 309 /* winsys_handle is in theory platform-specific */ 310 if (dpy->Platform != _EGL_PLATFORM_DRM) 311 return EGL_FALSE; 312 313 /* get shared handle */ 314 if (name) { 315 memset(&handle, 0, sizeof(handle)); 316 wsh.type = DRM_API_HANDLE_TYPE_SHARED; 317 if (!screen->resource_get_handle(screen, gimg->texture, &wsh)) { 318 return EGL_FALSE; 319 } 320 321 *name = wsh.handle; 322 } 323 324 /* get KMS handle */ 325 if (handle || stride) { 326 memset(&wsh, 0, sizeof(wsh)); 327 wsh.type = DRM_API_HANDLE_TYPE_KMS; 328 if (!screen->resource_get_handle(screen, gimg->texture, &wsh)) 329 return EGL_FALSE; 330 331 if (handle) 332 *handle = wsh.handle; 333 if (stride) 334 *stride = wsh.stride; 335 } 336 337 return EGL_TRUE; 338} 339