1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 2010 LunarG Inc. 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 * Authors: 25 * Chia-I Wu <olv@lunarg.com> 26 */ 27 28#include "main/errors.h" 29#include "main/texobj.h" 30#include "main/teximage.h" 31#include "util/u_inlines.h" 32#include "util/format/u_format.h" 33#include "st_cb_eglimage.h" 34#include "st_cb_fbo.h" 35#include "st_context.h" 36#include "st_texture.h" 37#include "st_format.h" 38#include "st_manager.h" 39#include "st_sampler_view.h" 40#include "util/u_surface.h" 41 42static bool 43is_format_supported(struct pipe_screen *screen, enum pipe_format format, 44 unsigned nr_samples, unsigned nr_storage_samples, 45 unsigned usage, bool *native_supported) 46{ 47 bool supported = screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 48 nr_samples, nr_storage_samples, 49 usage); 50 *native_supported = supported; 51 52 /* for sampling, some formats can be emulated.. it doesn't matter that 53 * the surface will have a format that the driver can't cope with because 54 * we'll give it sampler view formats that it can deal with and generate 55 * a shader variant that converts. 56 */ 57 if ((usage == PIPE_BIND_SAMPLER_VIEW) && !supported) { 58 switch (format) { 59 case PIPE_FORMAT_IYUV: 60 supported = screen->is_format_supported(screen, PIPE_FORMAT_R8_UNORM, 61 PIPE_TEXTURE_2D, nr_samples, 62 nr_storage_samples, usage); 63 break; 64 case PIPE_FORMAT_NV12: 65 supported = screen->is_format_supported(screen, PIPE_FORMAT_R8_UNORM, 66 PIPE_TEXTURE_2D, nr_samples, 67 nr_storage_samples, usage) && 68 screen->is_format_supported(screen, PIPE_FORMAT_R8G8_UNORM, 69 PIPE_TEXTURE_2D, nr_samples, 70 nr_storage_samples, usage); 71 break; 72 case PIPE_FORMAT_P010: 73 case PIPE_FORMAT_P012: 74 case PIPE_FORMAT_P016: 75 supported = screen->is_format_supported(screen, PIPE_FORMAT_R16_UNORM, 76 PIPE_TEXTURE_2D, nr_samples, 77 nr_storage_samples, usage) && 78 screen->is_format_supported(screen, PIPE_FORMAT_R16G16_UNORM, 79 PIPE_TEXTURE_2D, nr_samples, 80 nr_storage_samples, usage); 81 break; 82 case PIPE_FORMAT_Y210: 83 case PIPE_FORMAT_Y212: 84 case PIPE_FORMAT_Y216: 85 supported = screen->is_format_supported(screen, PIPE_FORMAT_R16G16_UNORM, 86 PIPE_TEXTURE_2D, nr_samples, 87 nr_storage_samples, usage) && 88 screen->is_format_supported(screen, PIPE_FORMAT_R16G16B16A16_UNORM, 89 PIPE_TEXTURE_2D, nr_samples, 90 nr_storage_samples, usage); 91 break; 92 case PIPE_FORMAT_Y410: 93 supported = screen->is_format_supported(screen, PIPE_FORMAT_R10G10B10A2_UNORM, 94 PIPE_TEXTURE_2D, nr_samples, 95 nr_storage_samples, usage); 96 break; 97 case PIPE_FORMAT_Y412: 98 case PIPE_FORMAT_Y416: 99 supported = screen->is_format_supported(screen, PIPE_FORMAT_R16G16B16A16_UNORM, 100 PIPE_TEXTURE_2D, nr_samples, 101 nr_storage_samples, usage); 102 break; 103 case PIPE_FORMAT_YUYV: 104 supported = screen->is_format_supported(screen, PIPE_FORMAT_R8G8_R8B8_UNORM, 105 PIPE_TEXTURE_2D, nr_samples, 106 nr_storage_samples, usage) || 107 (screen->is_format_supported(screen, PIPE_FORMAT_RG88_UNORM, 108 PIPE_TEXTURE_2D, nr_samples, 109 nr_storage_samples, usage) && 110 screen->is_format_supported(screen, PIPE_FORMAT_BGRA8888_UNORM, 111 PIPE_TEXTURE_2D, nr_samples, 112 nr_storage_samples, usage)); 113 break; 114 case PIPE_FORMAT_UYVY: 115 supported = screen->is_format_supported(screen, PIPE_FORMAT_G8R8_B8R8_UNORM, 116 PIPE_TEXTURE_2D, nr_samples, 117 nr_storage_samples, usage) || 118 (screen->is_format_supported(screen, PIPE_FORMAT_RG88_UNORM, 119 PIPE_TEXTURE_2D, nr_samples, 120 nr_storage_samples, usage) && 121 screen->is_format_supported(screen, PIPE_FORMAT_RGBA8888_UNORM, 122 PIPE_TEXTURE_2D, nr_samples, 123 nr_storage_samples, usage)); 124 break; 125 case PIPE_FORMAT_AYUV: 126 supported = screen->is_format_supported(screen, PIPE_FORMAT_RGBA8888_UNORM, 127 PIPE_TEXTURE_2D, nr_samples, 128 nr_storage_samples, usage); 129 break; 130 case PIPE_FORMAT_XYUV: 131 supported = screen->is_format_supported(screen, PIPE_FORMAT_RGBX8888_UNORM, 132 PIPE_TEXTURE_2D, nr_samples, 133 nr_storage_samples, usage); 134 break; 135 default: 136 break; 137 } 138 } 139 140 return supported; 141} 142 143static bool 144is_nv12_as_r8_g8b8_supported(struct pipe_screen *screen, struct st_egl_image *out, 145 unsigned usage, bool *native_supported) 146{ 147 if (out->format == PIPE_FORMAT_NV12 && 148 out->texture->format == PIPE_FORMAT_R8_G8B8_420_UNORM && 149 screen->is_format_supported(screen, PIPE_FORMAT_R8_G8B8_420_UNORM, 150 PIPE_TEXTURE_2D, 151 out->texture->nr_samples, 152 out->texture->nr_storage_samples, 153 usage)) { 154 *native_supported = false; 155 return true; 156 } 157 158 return false; 159} 160 161 162/** 163 * Return the gallium texture of an EGLImage. 164 */ 165static bool 166st_get_egl_image(struct gl_context *ctx, GLeglImageOES image_handle, 167 unsigned usage, const char *error, struct st_egl_image *out, 168 bool *native_supported) 169{ 170 struct st_context *st = st_context(ctx); 171 struct pipe_screen *screen = st->screen; 172 struct st_manager *smapi = 173 (struct st_manager *) st->iface.st_context_private; 174 175 if (!smapi || !smapi->get_egl_image) 176 return false; 177 178 memset(out, 0, sizeof(*out)); 179 if (!smapi->get_egl_image(smapi, (void *) image_handle, out)) { 180 /* image_handle does not refer to a valid EGL image object */ 181 _mesa_error(ctx, GL_INVALID_VALUE, "%s(image handle not found)", error); 182 return false; 183 } 184 185 if (!is_nv12_as_r8_g8b8_supported(screen, out, usage, native_supported) && 186 !is_format_supported(screen, out->format, out->texture->nr_samples, 187 out->texture->nr_storage_samples, usage, 188 native_supported)) { 189 /* unable to specify a texture object using the specified EGL image */ 190 pipe_resource_reference(&out->texture, NULL); 191 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(format not supported)", error); 192 return false; 193 } 194 195 ctx->Shared->HasExternallySharedImages = true; 196 return true; 197} 198 199/** 200 * Return the base format just like _mesa_base_fbo_format does. 201 */ 202static GLenum 203st_pipe_format_to_base_format(enum pipe_format format) 204{ 205 GLenum base_format; 206 207 if (util_format_is_depth_or_stencil(format)) { 208 if (util_format_is_depth_and_stencil(format)) { 209 base_format = GL_DEPTH_STENCIL; 210 } 211 else { 212 if (format == PIPE_FORMAT_S8_UINT) 213 base_format = GL_STENCIL_INDEX; 214 else 215 base_format = GL_DEPTH_COMPONENT; 216 } 217 } 218 else { 219 /* is this enough? */ 220 if (util_format_has_alpha(format)) 221 base_format = GL_RGBA; 222 else 223 base_format = GL_RGB; 224 } 225 226 return base_format; 227} 228 229static void 230st_egl_image_target_renderbuffer_storage(struct gl_context *ctx, 231 struct gl_renderbuffer *rb, 232 GLeglImageOES image_handle) 233{ 234 struct st_renderbuffer *strb = st_renderbuffer(rb); 235 struct st_egl_image stimg; 236 bool native_supported; 237 238 if (st_get_egl_image(ctx, image_handle, PIPE_BIND_RENDER_TARGET, 239 "glEGLImageTargetRenderbufferStorage", 240 &stimg, &native_supported)) { 241 struct pipe_context *pipe = st_context(ctx)->pipe; 242 struct pipe_surface *ps, surf_tmpl; 243 244 u_surface_default_template(&surf_tmpl, stimg.texture); 245 surf_tmpl.format = stimg.format; 246 surf_tmpl.u.tex.level = stimg.level; 247 surf_tmpl.u.tex.first_layer = stimg.layer; 248 surf_tmpl.u.tex.last_layer = stimg.layer; 249 ps = pipe->create_surface(pipe, stimg.texture, &surf_tmpl); 250 pipe_resource_reference(&stimg.texture, NULL); 251 252 if (!ps) 253 return; 254 255 strb->Base.Format = st_pipe_format_to_mesa_format(ps->format); 256 strb->Base._BaseFormat = st_pipe_format_to_base_format(ps->format); 257 strb->Base.InternalFormat = strb->Base._BaseFormat; 258 259 st_set_ws_renderbuffer_surface(strb, ps); 260 pipe_surface_reference(&ps, NULL); 261 } 262} 263 264static void 265st_bind_egl_image(struct gl_context *ctx, 266 struct gl_texture_object *texObj, 267 struct gl_texture_image *texImage, 268 struct st_egl_image *stimg, 269 bool tex_storage, 270 bool native_supported) 271{ 272 struct st_context *st = st_context(ctx); 273 struct st_texture_object *stObj; 274 struct st_texture_image *stImage; 275 GLenum internalFormat; 276 mesa_format texFormat; 277 278 /* map pipe format to base format */ 279 if (util_format_get_component_bits(stimg->format, 280 UTIL_FORMAT_COLORSPACE_RGB, 3) > 0) 281 internalFormat = GL_RGBA; 282 else 283 internalFormat = GL_RGB; 284 285 stObj = st_texture_object(texObj); 286 stImage = st_texture_image(texImage); 287 288 /* switch to surface based */ 289 if (!stObj->surface_based) { 290 _mesa_clear_texture_object(ctx, texObj, NULL); 291 stObj->surface_based = GL_TRUE; 292 } 293 294 /* TODO RequiredTextureImageUnits should probably be reset back 295 * to 1 somewhere if different texture is bound?? 296 */ 297 if (!native_supported) { 298 switch (stimg->format) { 299 case PIPE_FORMAT_NV12: 300 if (stimg->texture->format == PIPE_FORMAT_R8_G8B8_420_UNORM) { 301 texFormat = MESA_FORMAT_R8G8B8X8_UNORM; 302 texObj->RequiredTextureImageUnits = 1; 303 } else { 304 texFormat = MESA_FORMAT_R_UNORM8; 305 texObj->RequiredTextureImageUnits = 2; 306 } 307 break; 308 case PIPE_FORMAT_P010: 309 case PIPE_FORMAT_P012: 310 case PIPE_FORMAT_P016: 311 texFormat = MESA_FORMAT_R_UNORM16; 312 texObj->RequiredTextureImageUnits = 2; 313 break; 314 case PIPE_FORMAT_Y210: 315 case PIPE_FORMAT_Y212: 316 case PIPE_FORMAT_Y216: 317 texFormat = MESA_FORMAT_RG_UNORM16; 318 texObj->RequiredTextureImageUnits = 2; 319 break; 320 case PIPE_FORMAT_Y410: 321 texFormat = MESA_FORMAT_B10G10R10A2_UNORM; 322 internalFormat = GL_RGBA; 323 texObj->RequiredTextureImageUnits = 1; 324 break; 325 case PIPE_FORMAT_Y412: 326 case PIPE_FORMAT_Y416: 327 texFormat = MESA_FORMAT_RGBA_UNORM16; 328 internalFormat = GL_RGBA; 329 texObj->RequiredTextureImageUnits = 1; 330 break; 331 case PIPE_FORMAT_IYUV: 332 texFormat = MESA_FORMAT_R_UNORM8; 333 texObj->RequiredTextureImageUnits = 3; 334 break; 335 case PIPE_FORMAT_YUYV: 336 case PIPE_FORMAT_UYVY: 337 if (stimg->texture->format == PIPE_FORMAT_R8G8_R8B8_UNORM) { 338 texFormat = MESA_FORMAT_RG_RB_UNORM8; 339 texObj->RequiredTextureImageUnits = 1; 340 } else if (stimg->texture->format == PIPE_FORMAT_G8R8_B8R8_UNORM) { 341 texFormat = MESA_FORMAT_GR_BR_UNORM8; 342 texObj->RequiredTextureImageUnits = 1; 343 } else { 344 texFormat = MESA_FORMAT_RG_UNORM8; 345 texObj->RequiredTextureImageUnits = 2; 346 } 347 break; 348 case PIPE_FORMAT_AYUV: 349 texFormat = MESA_FORMAT_R8G8B8A8_UNORM; 350 internalFormat = GL_RGBA; 351 texObj->RequiredTextureImageUnits = 1; 352 break; 353 case PIPE_FORMAT_XYUV: 354 texFormat = MESA_FORMAT_R8G8B8X8_UNORM; 355 texObj->RequiredTextureImageUnits = 1; 356 break; 357 default: 358 unreachable("unexpected emulated format"); 359 break; 360 } 361 } else { 362 texFormat = st_pipe_format_to_mesa_format(stimg->format); 363 /* Use previously derived internalformat as specified by 364 * EXT_EGL_image_storage. 365 */ 366 if (tex_storage && texObj->Target == GL_TEXTURE_2D 367 && stimg->internalformat) { 368 internalFormat = stimg->internalformat; 369 if (internalFormat == GL_NONE) { 370 _mesa_error(ctx, GL_INVALID_OPERATION, __func__); 371 return; 372 } 373 } 374 } 375 assert(texFormat != MESA_FORMAT_NONE); 376 377 378 /* Minify texture size based on level set on the EGLImage. */ 379 uint32_t width = u_minify(stimg->texture->width0, stimg->level); 380 uint32_t height = u_minify(stimg->texture->height0, stimg->level); 381 382 _mesa_init_teximage_fields(ctx, texImage, width, height, 383 1, 0, internalFormat, texFormat); 384 385 pipe_resource_reference(&stObj->pt, stimg->texture); 386 st_texture_release_all_sampler_views(st, stObj); 387 pipe_resource_reference(&stImage->pt, stObj->pt); 388 if (st->screen->resource_changed) 389 st->screen->resource_changed(st->screen, stImage->pt); 390 391 stObj->surface_format = stimg->format; 392 stObj->level_override = stimg->level; 393 stObj->layer_override = stimg->layer; 394 395 _mesa_dirty_texobj(ctx, texObj); 396} 397 398static void 399st_egl_image_target_texture_2d(struct gl_context *ctx, GLenum target, 400 struct gl_texture_object *texObj, 401 struct gl_texture_image *texImage, 402 GLeglImageOES image_handle) 403{ 404 struct st_egl_image stimg; 405 bool native_supported; 406 407 if (!st_get_egl_image(ctx, image_handle, PIPE_BIND_SAMPLER_VIEW, 408 "glEGLImageTargetTexture2D", &stimg, 409 &native_supported)) 410 return; 411 412 st_bind_egl_image(ctx, texObj, texImage, &stimg, 413 target != GL_TEXTURE_EXTERNAL_OES, 414 native_supported); 415 pipe_resource_reference(&stimg.texture, NULL); 416} 417 418static void 419st_egl_image_target_tex_storage(struct gl_context *ctx, GLenum target, 420 struct gl_texture_object *texObj, 421 struct gl_texture_image *texImage, 422 GLeglImageOES image_handle) 423{ 424 struct st_egl_image stimg; 425 bool native_supported; 426 427 if (!st_get_egl_image(ctx, image_handle, PIPE_BIND_SAMPLER_VIEW, 428 "glEGLImageTargetTexture2D", &stimg, 429 &native_supported)) 430 return; 431 432 st_bind_egl_image(ctx, texObj, texImage, &stimg, true, native_supported); 433 pipe_resource_reference(&stimg.texture, NULL); 434} 435 436static GLboolean 437st_validate_egl_image(struct gl_context *ctx, GLeglImageOES image_handle) 438{ 439 struct st_context *st = st_context(ctx); 440 struct st_manager *smapi = 441 (struct st_manager *) st->iface.st_context_private; 442 443 return smapi->validate_egl_image(smapi, (void *)image_handle); 444} 445 446void 447st_init_eglimage_functions(struct dd_function_table *functions, 448 bool has_egl_image_validate) 449{ 450 functions->EGLImageTargetTexture2D = st_egl_image_target_texture_2d; 451 functions->EGLImageTargetTexStorage = st_egl_image_target_tex_storage; 452 functions->EGLImageTargetRenderbufferStorage = st_egl_image_target_renderbuffer_storage; 453 454 if (has_egl_image_validate) 455 functions->ValidateEGLImage = st_validate_egl_image; 456} 457