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 <GL/internal/dri_interface.h> 29#include "main/errors.h" 30#include "main/texobj.h" 31#include "main/teximage.h" 32#include "util/u_inlines.h" 33#include "util/format/u_format.h" 34#include "st_cb_eglimage.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 229void 230st_egl_image_target_renderbuffer_storage(struct gl_context *ctx, 231 struct gl_renderbuffer *rb, 232 GLeglImageOES image_handle) 233{ 234 struct st_egl_image stimg; 235 bool native_supported; 236 237 if (st_get_egl_image(ctx, image_handle, PIPE_BIND_RENDER_TARGET, 238 "glEGLImageTargetRenderbufferStorage", 239 &stimg, &native_supported)) { 240 struct pipe_context *pipe = st_context(ctx)->pipe; 241 struct pipe_surface *ps, surf_tmpl; 242 243 u_surface_default_template(&surf_tmpl, stimg.texture); 244 surf_tmpl.format = stimg.format; 245 surf_tmpl.u.tex.level = stimg.level; 246 surf_tmpl.u.tex.first_layer = stimg.layer; 247 surf_tmpl.u.tex.last_layer = stimg.layer; 248 ps = pipe->create_surface(pipe, stimg.texture, &surf_tmpl); 249 pipe_resource_reference(&stimg.texture, NULL); 250 251 if (!ps) 252 return; 253 254 rb->Format = st_pipe_format_to_mesa_format(ps->format); 255 rb->_BaseFormat = st_pipe_format_to_base_format(ps->format); 256 rb->InternalFormat = rb->_BaseFormat; 257 258 st_set_ws_renderbuffer_surface(rb, ps); 259 pipe_surface_reference(&ps, NULL); 260 } 261} 262 263static void 264st_bind_egl_image(struct gl_context *ctx, 265 struct gl_texture_object *texObj, 266 struct gl_texture_image *texImage, 267 struct st_egl_image *stimg, 268 bool tex_storage, 269 bool native_supported) 270{ 271 struct st_context *st = st_context(ctx); 272 GLenum internalFormat; 273 mesa_format texFormat; 274 275 if (stimg->internalformat) { 276 internalFormat = stimg->internalformat; 277 } else { 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 286 /* switch to surface based */ 287 if (!texObj->surface_based) { 288 _mesa_clear_texture_object(ctx, texObj, NULL); 289 texObj->surface_based = GL_TRUE; 290 } 291 292 /* TODO RequiredTextureImageUnits should probably be reset back 293 * to 1 somewhere if different texture is bound?? 294 */ 295 if (!native_supported) { 296 switch (stimg->format) { 297 case PIPE_FORMAT_NV12: 298 if (stimg->texture->format == PIPE_FORMAT_R8_G8B8_420_UNORM) { 299 texFormat = MESA_FORMAT_R8G8B8X8_UNORM; 300 texObj->RequiredTextureImageUnits = 1; 301 } else { 302 texFormat = MESA_FORMAT_R_UNORM8; 303 texObj->RequiredTextureImageUnits = 2; 304 } 305 break; 306 case PIPE_FORMAT_P010: 307 case PIPE_FORMAT_P012: 308 case PIPE_FORMAT_P016: 309 texFormat = MESA_FORMAT_R_UNORM16; 310 texObj->RequiredTextureImageUnits = 2; 311 break; 312 case PIPE_FORMAT_Y210: 313 case PIPE_FORMAT_Y212: 314 case PIPE_FORMAT_Y216: 315 texFormat = MESA_FORMAT_RG_UNORM16; 316 texObj->RequiredTextureImageUnits = 2; 317 break; 318 case PIPE_FORMAT_Y410: 319 texFormat = MESA_FORMAT_B10G10R10A2_UNORM; 320 internalFormat = GL_RGBA; 321 texObj->RequiredTextureImageUnits = 1; 322 break; 323 case PIPE_FORMAT_Y412: 324 case PIPE_FORMAT_Y416: 325 texFormat = MESA_FORMAT_RGBA_UNORM16; 326 internalFormat = GL_RGBA; 327 texObj->RequiredTextureImageUnits = 1; 328 break; 329 case PIPE_FORMAT_IYUV: 330 texFormat = MESA_FORMAT_R_UNORM8; 331 texObj->RequiredTextureImageUnits = 3; 332 break; 333 case PIPE_FORMAT_YUYV: 334 case PIPE_FORMAT_UYVY: 335 if (stimg->texture->format == PIPE_FORMAT_R8G8_R8B8_UNORM) { 336 texFormat = MESA_FORMAT_RG_RB_UNORM8; 337 texObj->RequiredTextureImageUnits = 1; 338 } else if (stimg->texture->format == PIPE_FORMAT_G8R8_B8R8_UNORM) { 339 texFormat = MESA_FORMAT_GR_BR_UNORM8; 340 texObj->RequiredTextureImageUnits = 1; 341 } else { 342 texFormat = MESA_FORMAT_RG_UNORM8; 343 texObj->RequiredTextureImageUnits = 2; 344 } 345 break; 346 case PIPE_FORMAT_AYUV: 347 texFormat = MESA_FORMAT_R8G8B8A8_UNORM; 348 internalFormat = GL_RGBA; 349 texObj->RequiredTextureImageUnits = 1; 350 break; 351 case PIPE_FORMAT_XYUV: 352 texFormat = MESA_FORMAT_R8G8B8X8_UNORM; 353 texObj->RequiredTextureImageUnits = 1; 354 break; 355 default: 356 unreachable("unexpected emulated format"); 357 break; 358 } 359 } else { 360 texFormat = st_pipe_format_to_mesa_format(stimg->format); 361 /* Use previously derived internalformat as specified by 362 * EXT_EGL_image_storage. 363 */ 364 if (tex_storage && texObj->Target == GL_TEXTURE_2D 365 && stimg->internalformat) { 366 internalFormat = stimg->internalformat; 367 if (internalFormat == GL_NONE) { 368 _mesa_error(ctx, GL_INVALID_OPERATION, __func__); 369 return; 370 } 371 } 372 } 373 assert(texFormat != MESA_FORMAT_NONE); 374 375 376 /* Minify texture size based on level set on the EGLImage. */ 377 uint32_t width = u_minify(stimg->texture->width0, stimg->level); 378 uint32_t height = u_minify(stimg->texture->height0, stimg->level); 379 380 _mesa_init_teximage_fields(ctx, texImage, width, height, 381 1, 0, internalFormat, texFormat); 382 383 pipe_resource_reference(&texObj->pt, stimg->texture); 384 st_texture_release_all_sampler_views(st, texObj); 385 pipe_resource_reference(&texImage->pt, texObj->pt); 386 if (st->screen->resource_changed) 387 st->screen->resource_changed(st->screen, texImage->pt); 388 389 texObj->surface_format = stimg->format; 390 391 switch (stimg->yuv_color_space) { 392 case __DRI_YUV_COLOR_SPACE_ITU_REC709: 393 texObj->yuv_color_space = GL_TEXTURE_YUV_COLOR_SPACE_REC709; 394 break; 395 case __DRI_YUV_COLOR_SPACE_ITU_REC2020: 396 texObj->yuv_color_space = GL_TEXTURE_YUV_COLOR_SPACE_REC2020; 397 break; 398 default: 399 texObj->yuv_color_space = GL_TEXTURE_YUV_COLOR_SPACE_REC601; 400 break; 401 } 402 403 if (stimg->yuv_range == __DRI_YUV_FULL_RANGE) 404 texObj->yuv_full_range = true; 405 406 texObj->level_override = stimg->level; 407 texObj->layer_override = stimg->layer; 408 409 _mesa_dirty_texobj(ctx, texObj); 410} 411 412void 413st_egl_image_target_texture_2d(struct gl_context *ctx, GLenum target, 414 struct gl_texture_object *texObj, 415 struct gl_texture_image *texImage, 416 GLeglImageOES image_handle) 417{ 418 struct st_egl_image stimg; 419 bool native_supported; 420 421 if (!st_get_egl_image(ctx, image_handle, PIPE_BIND_SAMPLER_VIEW, 422 "glEGLImageTargetTexture2D", &stimg, 423 &native_supported)) 424 return; 425 426 st_bind_egl_image(ctx, texObj, texImage, &stimg, 427 target != GL_TEXTURE_EXTERNAL_OES, 428 native_supported); 429 pipe_resource_reference(&stimg.texture, NULL); 430} 431 432void 433st_egl_image_target_tex_storage(struct gl_context *ctx, GLenum target, 434 struct gl_texture_object *texObj, 435 struct gl_texture_image *texImage, 436 GLeglImageOES image_handle) 437{ 438 struct st_egl_image stimg; 439 bool native_supported; 440 441 if (!st_get_egl_image(ctx, image_handle, PIPE_BIND_SAMPLER_VIEW, 442 "glEGLImageTargetTexture2D", &stimg, 443 &native_supported)) 444 return; 445 446 st_bind_egl_image(ctx, texObj, texImage, &stimg, true, native_supported); 447 pipe_resource_reference(&stimg.texture, NULL); 448} 449 450static GLboolean 451st_validate_egl_image(struct gl_context *ctx, GLeglImageOES image_handle) 452{ 453 struct st_context *st = st_context(ctx); 454 struct st_manager *smapi = 455 (struct st_manager *) st->iface.st_context_private; 456 457 return smapi->validate_egl_image(smapi, (void *)image_handle); 458} 459 460void 461st_init_eglimage_functions(struct dd_function_table *functions, 462 bool has_egl_image_validate) 463{ 464 if (has_egl_image_validate) 465 functions->ValidateEGLImage = st_validate_egl_image; 466} 467