1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 2014 Intel Corporation. All Rights Reserved. 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 17 * OR 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 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: 25 * Jason Ekstrand <jason.ekstrand@intel.com> 26 */ 27 28#include "context.h" 29#include "glheader.h" 30#include "errors.h" 31#include "enums.h" 32#include "copyimage.h" 33#include "teximage.h" 34#include "texobj.h" 35#include "fbobject.h" 36#include "textureview.h" 37#include "glformats.h" 38 39enum mesa_block_class { 40 BLOCK_CLASS_128_BITS, 41 BLOCK_CLASS_64_BITS 42}; 43 44/** 45 * Prepare the source or destination resource. This involves error 46 * checking and returning the relevant gl_texture_image or gl_renderbuffer. 47 * Note that one of the resulting tex_image or renderbuffer pointers will be 48 * NULL and the other will be non-null. 49 * 50 * \param name the texture or renderbuffer name 51 * \param target One of GL_TEXTURE_x target or GL_RENDERBUFFER 52 * \param level mipmap level 53 * \param z src or dest Z 54 * \param depth number of slices/faces/layers to copy 55 * \param tex_image returns a pointer to a texture image 56 * \param renderbuffer returns a pointer to a renderbuffer 57 * \return true if success, false if error 58 */ 59static bool 60prepare_target_err(struct gl_context *ctx, GLuint name, GLenum target, 61 int level, int z, int depth, 62 struct gl_texture_image **tex_image, 63 struct gl_renderbuffer **renderbuffer, 64 mesa_format *format, 65 GLenum *internalFormat, 66 GLuint *width, 67 GLuint *height, 68 GLuint *num_samples, 69 const char *dbg_prefix) 70{ 71 if (name == 0) { 72 _mesa_error(ctx, GL_INVALID_VALUE, 73 "glCopyImageSubData(%sName = %d)", dbg_prefix, name); 74 return false; 75 } 76 77 /* 78 * INVALID_ENUM is generated 79 * * if either <srcTarget> or <dstTarget> 80 * - is not RENDERBUFFER or a valid non-proxy texture target 81 * - is TEXTURE_BUFFER, or 82 * - is one of the cubemap face selectors described in table 3.17, 83 */ 84 switch (target) { 85 case GL_RENDERBUFFER: 86 /* Not a texture target, but valid */ 87 case GL_TEXTURE_1D: 88 case GL_TEXTURE_1D_ARRAY: 89 case GL_TEXTURE_2D: 90 case GL_TEXTURE_3D: 91 case GL_TEXTURE_CUBE_MAP: 92 case GL_TEXTURE_RECTANGLE: 93 case GL_TEXTURE_2D_ARRAY: 94 case GL_TEXTURE_CUBE_MAP_ARRAY: 95 case GL_TEXTURE_2D_MULTISAMPLE: 96 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 97 /* These are all valid */ 98 break; 99 case GL_TEXTURE_EXTERNAL_OES: 100 /* Only exists in ES */ 101 case GL_TEXTURE_BUFFER: 102 default: 103 _mesa_error(ctx, GL_INVALID_ENUM, 104 "glCopyImageSubData(%sTarget = %s)", dbg_prefix, 105 _mesa_enum_to_string(target)); 106 return false; 107 } 108 109 if (target == GL_RENDERBUFFER) { 110 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name); 111 112 if (!rb) { 113 _mesa_error(ctx, GL_INVALID_VALUE, 114 "glCopyImageSubData(%sName = %u)", dbg_prefix, name); 115 return false; 116 } 117 118 if (!rb->Name) { 119 _mesa_error(ctx, GL_INVALID_OPERATION, 120 "glCopyImageSubData(%sName incomplete)", dbg_prefix); 121 return false; 122 } 123 124 if (level != 0) { 125 _mesa_error(ctx, GL_INVALID_VALUE, 126 "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level); 127 return false; 128 } 129 130 *renderbuffer = rb; 131 *format = rb->Format; 132 *internalFormat = rb->InternalFormat; 133 *width = rb->Width; 134 *height = rb->Height; 135 *num_samples = rb->NumSamples; 136 *tex_image = NULL; 137 } else { 138 struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name); 139 140 if (!texObj) { 141 /* 142 * From GL_ARB_copy_image specification: 143 * "INVALID_VALUE is generated if either <srcName> or <dstName> does 144 * not correspond to a valid renderbuffer or texture object according 145 * to the corresponding target parameter." 146 */ 147 _mesa_error(ctx, GL_INVALID_VALUE, 148 "glCopyImageSubData(%sName = %u)", dbg_prefix, name); 149 return false; 150 } 151 152 /* The ARB_copy_image specification says: 153 * 154 * "INVALID_OPERATION is generated if either object is a texture and 155 * the texture is not complete (as defined in section 3.9.14)" 156 * 157 * The cited section says: 158 * 159 * "Using the preceding definitions, a texture is complete unless any 160 * of the following conditions hold true: [...] 161 * 162 * * The minification filter requires a mipmap (is neither NEAREST 163 * nor LINEAR), and the texture is not mipmap complete." 164 * 165 * This imposes the bizarre restriction that glCopyImageSubData requires 166 * mipmap completion based on the sampler minification filter, even 167 * though the call fundamentally ignores the sampler. Additionally, it 168 * doesn't work with texture units, so it can't consider any bound 169 * separate sampler objects. It appears that you're supposed to use 170 * the sampler object which is built-in to the texture object. 171 * 172 * dEQP and the Android CTS mandate this behavior, and the Khronos 173 * GL and ES working groups both affirmed that this is unfortunate but 174 * correct. See https://cvs.khronos.org/bugzilla/show_bug.cgi?id=16224. 175 * 176 * Integer textures with filtering cause another completeness snag: 177 * 178 * "Any of: 179 * – The internal format of the texture is integer (see table 8.12). 180 * – The internal format is STENCIL_INDEX. 181 * – The internal format is DEPTH_STENCIL, and the value of 182 * DEPTH_STENCIL_TEXTURE_MODE for the texture is STENCIL_INDEX. 183 * and either the magnification filter is not NEAREST, or the 184 * minification filter is neither NEAREST nor 185 * NEAREST_MIPMAP_NEAREST." 186 * 187 * However, applications in the wild (such as "Total War: WARHAMMER") 188 * appear to call glCopyImageSubData with integer textures and the 189 * default mipmap filters of GL_LINEAR and GL_NEAREST_MIPMAP_LINEAR, 190 * which would be considered incomplete, but expect this to work. In 191 * fact, until VK-GL-CTS commit fef80039ff875a51806b54d151c5f2d0c12da, 192 * the GL 4.5 CTS contained three tests which did the exact same thing 193 * by accident, and all conformant implementations allowed it. 194 * 195 * A proposal was made to amend the spec to say "is not complete (as 196 * defined in section <X>, but ignoring format-based completeness 197 * rules)" to allow this case. It makes some sense, given that 198 * glCopyImageSubData copies raw data without considering format. 199 * While the official edits have not yet been made, the OpenGL 200 * working group agreed with the idea of allowing this behavior. 201 * 202 * To ignore formats, we check texObj->_MipmapComplete directly 203 * rather than calling _mesa_is_texture_complete(). 204 */ 205 _mesa_test_texobj_completeness(ctx, texObj); 206 const bool texture_complete_aside_from_formats = 207 _mesa_is_mipmap_filter(&texObj->Sampler) ? texObj->_MipmapComplete 208 : texObj->_BaseComplete; 209 if (!texture_complete_aside_from_formats) { 210 _mesa_error(ctx, GL_INVALID_OPERATION, 211 "glCopyImageSubData(%sName incomplete)", dbg_prefix); 212 return false; 213 } 214 215 /* Note that target will not be a cube face name */ 216 if (texObj->Target != target) { 217 /* 218 * From GL_ARB_copy_image_specification: 219 * "INVALID_ENUM is generated if the target does not match the type 220 * of the object." 221 */ 222 _mesa_error(ctx, GL_INVALID_ENUM, 223 "glCopyImageSubData(%sTarget = %s)", dbg_prefix, 224 _mesa_enum_to_string(target)); 225 return false; 226 } 227 228 if (level < 0 || level >= MAX_TEXTURE_LEVELS) { 229 _mesa_error(ctx, GL_INVALID_VALUE, 230 "glCopyImageSubData(%sLevel = %d)", dbg_prefix, level); 231 return false; 232 } 233 234 if (target == GL_TEXTURE_CUBE_MAP) { 235 int i; 236 237 assert(z < MAX_FACES); /* should have been caught earlier */ 238 239 /* make sure all the cube faces are present */ 240 for (i = 0; i < depth; i++) { 241 if (!texObj->Image[z+i][level]) { 242 /* missing cube face */ 243 _mesa_error(ctx, GL_INVALID_VALUE, 244 "glCopyImageSubData(missing cube face)"); 245 return false; 246 } 247 } 248 249 *tex_image = texObj->Image[z][level]; 250 } 251 else { 252 *tex_image = _mesa_select_tex_image(texObj, target, level); 253 } 254 255 if (!*tex_image) { 256 _mesa_error(ctx, GL_INVALID_VALUE, 257 "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level); 258 return false; 259 } 260 261 *renderbuffer = NULL; 262 *format = (*tex_image)->TexFormat; 263 *internalFormat = (*tex_image)->InternalFormat; 264 *width = (*tex_image)->Width; 265 *height = (*tex_image)->Height; 266 *num_samples = (*tex_image)->NumSamples; 267 } 268 269 return true; 270} 271 272static void 273prepare_target(struct gl_context *ctx, GLuint name, GLenum target, 274 int level, int z, 275 struct gl_texture_image **texImage, 276 struct gl_renderbuffer **renderbuffer) 277{ 278 if (target == GL_RENDERBUFFER) { 279 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name); 280 281 *renderbuffer = rb; 282 *texImage = NULL; 283 } else { 284 struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name); 285 286 if (target == GL_TEXTURE_CUBE_MAP) { 287 *texImage = texObj->Image[z][level]; 288 } 289 else { 290 *texImage = _mesa_select_tex_image(texObj, target, level); 291 } 292 293 *renderbuffer = NULL; 294 } 295} 296 297/** 298 * Check that the x,y,z,width,height,region is within the texture image 299 * dimensions. 300 * \return true if bounds OK, false if regions is out of bounds 301 */ 302static bool 303check_region_bounds(struct gl_context *ctx, 304 GLenum target, 305 const struct gl_texture_image *tex_image, 306 const struct gl_renderbuffer *renderbuffer, 307 int x, int y, int z, int width, int height, int depth, 308 const char *dbg_prefix) 309{ 310 int surfWidth, surfHeight, surfDepth; 311 312 if (width < 0 || height < 0 || depth < 0) { 313 _mesa_error(ctx, GL_INVALID_VALUE, 314 "glCopyImageSubData(%sWidth, %sHeight, or %sDepth is negative)", 315 dbg_prefix, dbg_prefix, dbg_prefix); 316 return false; 317 } 318 319 if (x < 0 || y < 0 || z < 0) { 320 _mesa_error(ctx, GL_INVALID_VALUE, 321 "glCopyImageSubData(%sX, %sY, or %sZ is negative)", 322 dbg_prefix, dbg_prefix, dbg_prefix); 323 return false; 324 } 325 326 /* Check X direction */ 327 if (target == GL_RENDERBUFFER) { 328 surfWidth = renderbuffer->Width; 329 } 330 else { 331 surfWidth = tex_image->Width; 332 } 333 334 if (x + width > surfWidth) { 335 _mesa_error(ctx, GL_INVALID_VALUE, 336 "glCopyImageSubData(%sX or %sWidth exceeds image bounds)", 337 dbg_prefix, dbg_prefix); 338 return false; 339 } 340 341 /* Check Y direction */ 342 switch (target) { 343 case GL_RENDERBUFFER: 344 surfHeight = renderbuffer->Height; 345 break; 346 case GL_TEXTURE_1D: 347 case GL_TEXTURE_1D_ARRAY: 348 surfHeight = 1; 349 break; 350 default: 351 surfHeight = tex_image->Height; 352 } 353 354 if (y + height > surfHeight) { 355 _mesa_error(ctx, GL_INVALID_VALUE, 356 "glCopyImageSubData(%sY or %sHeight exceeds image bounds)", 357 dbg_prefix, dbg_prefix); 358 return false; 359 } 360 361 /* Check Z direction */ 362 switch (target) { 363 case GL_RENDERBUFFER: 364 case GL_TEXTURE_1D: 365 case GL_TEXTURE_2D: 366 case GL_TEXTURE_2D_MULTISAMPLE: 367 case GL_TEXTURE_RECTANGLE: 368 surfDepth = 1; 369 break; 370 case GL_TEXTURE_CUBE_MAP: 371 surfDepth = 6; 372 break; 373 case GL_TEXTURE_1D_ARRAY: 374 surfDepth = tex_image->Height; 375 break; 376 default: 377 surfDepth = tex_image->Depth; 378 } 379 380 if (z < 0 || z + depth > surfDepth) { 381 _mesa_error(ctx, GL_INVALID_VALUE, 382 "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)", 383 dbg_prefix, dbg_prefix); 384 return false; 385 } 386 387 return true; 388} 389 390static bool 391compressed_format_compatible(const struct gl_context *ctx, 392 GLenum compressedFormat, GLenum otherFormat) 393{ 394 enum mesa_block_class compressedClass, otherClass; 395 396 /* Two view-incompatible compressed formats are never compatible. */ 397 if (_mesa_is_compressed_format(ctx, otherFormat)) { 398 return false; 399 } 400 401 /* 402 * From ARB_copy_image spec: 403 * Table 4.X.1 (Compatible internal formats for copying between 404 * compressed and uncompressed internal formats) 405 * --------------------------------------------------------------------- 406 * | Texel / | Uncompressed | | 407 * | Block | internal format | Compressed internal format | 408 * | size | | | 409 * --------------------------------------------------------------------- 410 * | 128-bit | RGBA32UI, | COMPRESSED_RGBA_S3TC_DXT3_EXT, | 411 * | | RGBA32I, | COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,| 412 * | | RGBA32F | COMPRESSED_RGBA_S3TC_DXT5_EXT, | 413 * | | | COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,| 414 * | | | COMPRESSED_RG_RGTC2, | 415 * | | | COMPRESSED_SIGNED_RG_RGTC2, | 416 * | | | COMPRESSED_RGBA_BPTC_UNORM, | 417 * | | | COMPRESSED_SRGB_ALPHA_BPTC_UNORM, | 418 * | | | COMPRESSED_RGB_BPTC_SIGNED_FLOAT, | 419 * | | | COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT | 420 * --------------------------------------------------------------------- 421 * | 64-bit | RGBA16F, RG32F, | COMPRESSED_RGB_S3TC_DXT1_EXT, | 422 * | | RGBA16UI, RG32UI, | COMPRESSED_SRGB_S3TC_DXT1_EXT, | 423 * | | RGBA16I, RG32I, | COMPRESSED_RGBA_S3TC_DXT1_EXT, | 424 * | | RGBA16, | COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,| 425 * | | RGBA16_SNORM | COMPRESSED_RED_RGTC1, | 426 * | | | COMPRESSED_SIGNED_RED_RGTC1 | 427 * --------------------------------------------------------------------- 428 */ 429 430 switch (compressedFormat) { 431 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: 432 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: 433 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: 434 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: 435 case GL_COMPRESSED_RG_RGTC2: 436 case GL_COMPRESSED_SIGNED_RG_RGTC2: 437 case GL_COMPRESSED_RGBA_BPTC_UNORM: 438 case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: 439 case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: 440 case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: 441 compressedClass = BLOCK_CLASS_128_BITS; 442 break; 443 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: 444 case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: 445 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: 446 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: 447 case GL_COMPRESSED_RED_RGTC1: 448 case GL_COMPRESSED_SIGNED_RED_RGTC1: 449 compressedClass = BLOCK_CLASS_64_BITS; 450 break; 451 case GL_COMPRESSED_RGBA8_ETC2_EAC: 452 case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: 453 case GL_COMPRESSED_RG11_EAC: 454 case GL_COMPRESSED_SIGNED_RG11_EAC: 455 if (_mesa_is_gles(ctx)) 456 compressedClass = BLOCK_CLASS_128_BITS; 457 else 458 return false; 459 break; 460 case GL_COMPRESSED_RGB8_ETC2: 461 case GL_COMPRESSED_SRGB8_ETC2: 462 case GL_COMPRESSED_R11_EAC: 463 case GL_COMPRESSED_SIGNED_R11_EAC: 464 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: 465 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: 466 if (_mesa_is_gles(ctx)) 467 compressedClass = BLOCK_CLASS_64_BITS; 468 else 469 return false; 470 break; 471 default: 472 if (_mesa_is_gles(ctx) && _mesa_is_astc_format(compressedFormat)) 473 compressedClass = BLOCK_CLASS_128_BITS; 474 else 475 return false; 476 break; 477 } 478 479 switch (otherFormat) { 480 case GL_RGBA32UI: 481 case GL_RGBA32I: 482 case GL_RGBA32F: 483 otherClass = BLOCK_CLASS_128_BITS; 484 break; 485 case GL_RGBA16F: 486 case GL_RG32F: 487 case GL_RGBA16UI: 488 case GL_RG32UI: 489 case GL_RGBA16I: 490 case GL_RG32I: 491 case GL_RGBA16: 492 case GL_RGBA16_SNORM: 493 otherClass = BLOCK_CLASS_64_BITS; 494 break; 495 default: 496 return false; 497 } 498 499 return compressedClass == otherClass; 500} 501 502static bool 503copy_format_compatible(const struct gl_context *ctx, 504 GLenum srcFormat, GLenum dstFormat) 505{ 506 /* 507 * From ARB_copy_image spec: 508 * For the purposes of CopyImageSubData, two internal formats 509 * are considered compatible if any of the following conditions are 510 * met: 511 * * the formats are the same, 512 * * the formats are considered compatible according to the 513 * compatibility rules used for texture views as defined in 514 * section 3.9.X. In particular, if both internal formats are listed 515 * in the same entry of Table 3.X.2, they are considered compatible, or 516 * * one format is compressed and the other is uncompressed and 517 * Table 4.X.1 lists the two formats in the same row. 518 */ 519 520 if (_mesa_texture_view_compatible_format(ctx, srcFormat, dstFormat)) { 521 /* Also checks if formats are equal. */ 522 return true; 523 } else if (_mesa_is_compressed_format(ctx, srcFormat)) { 524 return compressed_format_compatible(ctx, srcFormat, dstFormat); 525 } else if (_mesa_is_compressed_format(ctx, dstFormat)) { 526 return compressed_format_compatible(ctx, dstFormat, srcFormat); 527 } 528 529 return false; 530} 531 532static void 533copy_image_subdata(struct gl_context *ctx, 534 struct gl_texture_image *srcTexImage, 535 struct gl_renderbuffer *srcRenderbuffer, 536 int srcX, int srcY, int srcZ, int srcLevel, 537 struct gl_texture_image *dstTexImage, 538 struct gl_renderbuffer *dstRenderbuffer, 539 int dstX, int dstY, int dstZ, int dstLevel, 540 int srcWidth, int srcHeight, int srcDepth) 541{ 542 /* loop over 2D slices/faces/layers */ 543 for (int i = 0; i < srcDepth; ++i) { 544 int newSrcZ = srcZ + i; 545 int newDstZ = dstZ + i; 546 547 if (srcTexImage && 548 srcTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) { 549 /* need to update srcTexImage pointer for the cube face */ 550 assert(srcZ + i < MAX_FACES); 551 srcTexImage = srcTexImage->TexObject->Image[srcZ + i][srcLevel]; 552 assert(srcTexImage); 553 newSrcZ = 0; 554 } 555 556 if (dstTexImage && 557 dstTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) { 558 /* need to update dstTexImage pointer for the cube face */ 559 assert(dstZ + i < MAX_FACES); 560 dstTexImage = dstTexImage->TexObject->Image[dstZ + i][dstLevel]; 561 assert(dstTexImage); 562 newDstZ = 0; 563 } 564 565 ctx->Driver.CopyImageSubData(ctx, 566 srcTexImage, srcRenderbuffer, 567 srcX, srcY, newSrcZ, 568 dstTexImage, dstRenderbuffer, 569 dstX, dstY, newDstZ, 570 srcWidth, srcHeight); 571 } 572} 573 574void GLAPIENTRY 575_mesa_CopyImageSubData_no_error(GLuint srcName, GLenum srcTarget, GLint srcLevel, 576 GLint srcX, GLint srcY, GLint srcZ, 577 GLuint dstName, GLenum dstTarget, GLint dstLevel, 578 GLint dstX, GLint dstY, GLint dstZ, 579 GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) 580{ 581 struct gl_texture_image *srcTexImage, *dstTexImage; 582 struct gl_renderbuffer *srcRenderbuffer, *dstRenderbuffer; 583 584 GET_CURRENT_CONTEXT(ctx); 585 586 prepare_target(ctx, srcName, srcTarget, srcLevel, srcZ, &srcTexImage, 587 &srcRenderbuffer); 588 589 prepare_target(ctx, dstName, dstTarget, dstLevel, dstZ, &dstTexImage, 590 &dstRenderbuffer); 591 592 copy_image_subdata(ctx, srcTexImage, srcRenderbuffer, srcX, srcY, srcZ, 593 srcLevel, dstTexImage, dstRenderbuffer, dstX, dstY, dstZ, 594 dstLevel, srcWidth, srcHeight, srcDepth); 595} 596 597void GLAPIENTRY 598_mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel, 599 GLint srcX, GLint srcY, GLint srcZ, 600 GLuint dstName, GLenum dstTarget, GLint dstLevel, 601 GLint dstX, GLint dstY, GLint dstZ, 602 GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) 603{ 604 GET_CURRENT_CONTEXT(ctx); 605 struct gl_texture_image *srcTexImage, *dstTexImage; 606 struct gl_renderbuffer *srcRenderbuffer, *dstRenderbuffer; 607 mesa_format srcFormat, dstFormat; 608 GLenum srcIntFormat, dstIntFormat; 609 GLuint src_w, src_h, dst_w, dst_h; 610 GLuint src_bw, src_bh, dst_bw, dst_bh; 611 GLuint src_num_samples, dst_num_samples; 612 int dstWidth, dstHeight, dstDepth; 613 614 if (MESA_VERBOSE & VERBOSE_API) 615 _mesa_debug(ctx, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, " 616 "%u, %s, %d, %d, %d, %d, " 617 "%d, %d, %d)\n", 618 srcName, _mesa_enum_to_string(srcTarget), srcLevel, 619 srcX, srcY, srcZ, 620 dstName, _mesa_enum_to_string(dstTarget), dstLevel, 621 dstX, dstY, dstZ, 622 srcWidth, srcHeight, srcDepth); 623 624 if (!ctx->Extensions.ARB_copy_image) { 625 _mesa_error(ctx, GL_INVALID_OPERATION, 626 "glCopyImageSubData(extension not available)"); 627 return; 628 } 629 630 if (!prepare_target_err(ctx, srcName, srcTarget, srcLevel, srcZ, srcDepth, 631 &srcTexImage, &srcRenderbuffer, &srcFormat, 632 &srcIntFormat, &src_w, &src_h, &src_num_samples, 633 "src")) 634 return; 635 636 if (!prepare_target_err(ctx, dstName, dstTarget, dstLevel, dstZ, srcDepth, 637 &dstTexImage, &dstRenderbuffer, &dstFormat, 638 &dstIntFormat, &dst_w, &dst_h, &dst_num_samples, 639 "dst")) 640 return; 641 642 _mesa_get_format_block_size(srcFormat, &src_bw, &src_bh); 643 644 /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core Profile 645 * spec says: 646 * 647 * An INVALID_VALUE error is generated if the dimensions of either 648 * subregion exceeds the boundaries of the corresponding image object, 649 * or if the image format is compressed and the dimensions of the 650 * subregion fail to meet the alignment constraints of the format. 651 * 652 * and Section 8.7 (Compressed Texture Images) says: 653 * 654 * An INVALID_OPERATION error is generated if any of the following 655 * conditions occurs: 656 * 657 * * width is not a multiple of four, and width + xoffset is not 658 * equal to the value of TEXTURE_WIDTH. 659 * * height is not a multiple of four, and height + yoffset is not 660 * equal to the value of TEXTURE_HEIGHT. 661 * 662 * so we take that to mean that you can copy the "last" block of a 663 * compressed texture image even if it's smaller than the minimum block 664 * dimensions. 665 */ 666 if ((srcX % src_bw != 0) || (srcY % src_bh != 0) || 667 (srcWidth % src_bw != 0 && (srcX + srcWidth) != src_w) || 668 (srcHeight % src_bh != 0 && (srcY + srcHeight) != src_h)) { 669 _mesa_error(ctx, GL_INVALID_VALUE, 670 "glCopyImageSubData(unaligned src rectangle)"); 671 return; 672 } 673 674 _mesa_get_format_block_size(dstFormat, &dst_bw, &dst_bh); 675 if ((dstX % dst_bw != 0) || (dstY % dst_bh != 0)) { 676 _mesa_error(ctx, GL_INVALID_VALUE, 677 "glCopyImageSubData(unaligned dst rectangle)"); 678 return; 679 } 680 681 /* From the GL_ARB_copy_image spec: 682 * 683 * "The dimensions are always specified in texels, even for compressed 684 * texture formats. But it should be noted that if only one of the 685 * source and destination textures is compressed then the number of 686 * texels touched in the compressed image will be a factor of the 687 * block size larger than in the uncompressed image." 688 * 689 * So, if copying from compressed to uncompressed, the dest region is 690 * shrunk by the src block size factor. If copying from uncompressed 691 * to compressed, the dest region is grown by the dest block size factor. 692 * Note that we're passed the _source_ width, height, depth and those 693 * dimensions are never changed. 694 */ 695 dstWidth = srcWidth * dst_bw / src_bw; 696 dstHeight = srcHeight * dst_bh / src_bh; 697 dstDepth = srcDepth; 698 699 if (!check_region_bounds(ctx, srcTarget, srcTexImage, srcRenderbuffer, 700 srcX, srcY, srcZ, srcWidth, srcHeight, srcDepth, 701 "src")) 702 return; 703 704 if (!check_region_bounds(ctx, dstTarget, dstTexImage, dstRenderbuffer, 705 dstX, dstY, dstZ, dstWidth, dstHeight, dstDepth, 706 "dst")) 707 return; 708 709 /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core Profile 710 * spec says: 711 * 712 * An INVALID_OPERATION error is generated if either object is a texture 713 * and the texture is not complete, if the source and destination internal 714 * formats are not compatible, or if the number of samples do not match. 715 */ 716 if (!copy_format_compatible(ctx, srcIntFormat, dstIntFormat)) { 717 _mesa_error(ctx, GL_INVALID_OPERATION, 718 "glCopyImageSubData(internalFormat mismatch)"); 719 return; 720 } 721 722 if (src_num_samples != dst_num_samples) { 723 _mesa_error(ctx, GL_INVALID_OPERATION, 724 "glCopyImageSubData(number of samples mismatch)"); 725 return; 726 } 727 728 copy_image_subdata(ctx, srcTexImage, srcRenderbuffer, srcX, srcY, srcZ, 729 srcLevel, dstTexImage, dstRenderbuffer, dstX, dstY, dstZ, 730 dstLevel, srcWidth, srcHeight, srcDepth); 731} 732