void GLAPIENTRY _mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) { GET_CURRENT_CONTEXT(ctx); GLuint tmpTexNames[2] = { 0, 0 }; struct gl_texture_object *srcTexObj, *dstTexObj; struct gl_texture_image *srcTexImage, *dstTexImage; GLuint src_w, src_h, dst_w, dst_h; GLuint src_bw, src_bh, dst_bw, dst_bh; int i; if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, " "%u, %s, %d, %d, %d, %d, " "%d, %d, %d)\n", srcName, _mesa_enum_to_string(srcTarget), srcLevel, srcX, srcY, srcZ, dstName, _mesa_enum_to_string(dstTarget), dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcWidth); if (!ctx->Extensions.ARB_copy_image) { _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyImageSubData(extension not available)"); return; } if (!prepare_target(ctx, srcName, &srcTarget, srcLevel, &srcTexObj, &srcTexImage, &tmpTexNames[0], &src_w, &src_h, "src")) goto cleanup; if (!prepare_target(ctx, dstName, &dstTarget, dstLevel, &dstTexObj, &dstTexImage, &tmpTexNames[1], &dst_w, &dst_h, "dst")) goto cleanup; _mesa_get_format_block_size(srcTexImage->TexFormat, &src_bw, &src_bh); /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core Profile * spec says: * * An INVALID_VALUE error is generated if the dimensions of either * subregion exceeds the boundaries of the corresponding image object, * or if the image format is compressed and the dimensions of the * subregion fail to meet the alignment constraints of the format. * * and Section 8.7 (Compressed Texture Images) says: * * An INVALID_OPERATION error is generated if any of the following * conditions occurs: * * * width is not a multiple of four, and width + xoffset is not * equal to the value of TEXTURE_WIDTH. * * height is not a multiple of four, and height + yoffset is not * equal to the value of TEXTURE_HEIGHT. * * so we take that to mean that you can copy the "last" block of a * compressed texture image even if it's smaller than the minimum block * dimensions. */ if ((srcX % src_bw != 0) || (srcY % src_bh != 0) || (srcWidth % src_bw != 0 && (srcX + srcWidth) != src_w) || (srcHeight % src_bh != 0 && (srcY + srcHeight) != src_h)) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(unaligned src rectangle)"); goto cleanup; } _mesa_get_format_block_size(dstTexImage->TexFormat, &dst_bw, &dst_bh); if ((dstX % dst_bw != 0) || (dstY % dst_bh != 0)) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(unaligned dst rectangle)"); goto cleanup; } if (!check_region_bounds(ctx, srcTexImage, srcX, srcY, srcZ, srcWidth, srcHeight, srcDepth, "src")) goto cleanup; if (!check_region_bounds(ctx, dstTexImage, dstX, dstY, dstZ, (srcWidth / src_bw) * dst_bw, (srcHeight / src_bh) * dst_bh, srcDepth, "dst")) goto cleanup; if (!copy_format_compatible(ctx, srcTexImage->InternalFormat, dstTexImage->InternalFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyImageSubData(internalFormat mismatch)"); goto cleanup; } for (i = 0; i < srcDepth; ++i) { int srcNewZ, dstNewZ; if (srcTexObj->Target == GL_TEXTURE_CUBE_MAP) { srcTexImage = srcTexObj->Image[i + srcZ][srcLevel]; srcNewZ = 0; } else { srcNewZ = srcZ + i; } if (dstTexObj->Target == GL_TEXTURE_CUBE_MAP) { dstTexImage = dstTexObj->Image[i + dstZ][dstLevel]; dstNewZ = 0; } else { dstNewZ = dstZ + i; } ctx->Driver.CopyImageSubData(ctx, srcTexImage, srcX, srcY, srcNewZ, dstTexImage, dstX, dstY, dstNewZ, srcWidth, srcHeight); } cleanup: _mesa_DeleteTextures(2, tmpTexNames); }
void GLAPIENTRY _mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) { GET_CURRENT_CONTEXT(ctx); GLuint tmpTexNames[2] = { 0, 0 }; struct gl_texture_object *srcTexObj, *dstTexObj; struct gl_texture_image *srcTexImage, *dstTexImage; GLuint src_bw, src_bh, dst_bw, dst_bh; int i; if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, " "%u, %s, %d, %d, %d, %d, " "%d, %d, %d)\n", srcName, _mesa_lookup_enum_by_nr(srcTarget), srcLevel, srcX, srcY, srcZ, dstName, _mesa_lookup_enum_by_nr(dstTarget), dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcWidth); if (!ctx->Extensions.ARB_copy_image) { _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyImageSubData(extension not available)"); return; } if (!prepare_target(ctx, srcName, &srcTarget, srcLevel, &srcTexObj, &srcTexImage, &tmpTexNames[0], "src")) goto cleanup; if (!prepare_target(ctx, dstName, &dstTarget, dstLevel, &dstTexObj, &dstTexImage, &tmpTexNames[1], "dst")) goto cleanup; _mesa_get_format_block_size(srcTexImage->TexFormat, &src_bw, &src_bh); if ((srcX % src_bw != 0) || (srcY % src_bh != 0) || (srcWidth % src_bw != 0) || (srcHeight % src_bh != 0)) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(unaligned src rectangle)"); goto cleanup; } _mesa_get_format_block_size(dstTexImage->TexFormat, &dst_bw, &dst_bh); if ((dstX % dst_bw != 0) || (dstY % dst_bh != 0)) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(unaligned dst rectangle)"); goto cleanup; } if (!check_region_bounds(ctx, srcTexImage, srcX, srcY, srcZ, srcWidth, srcHeight, srcDepth, "src")) goto cleanup; if (!check_region_bounds(ctx, dstTexImage, dstX, dstY, dstZ, (srcWidth / src_bw) * dst_bw, (srcHeight / src_bh) * dst_bh, srcDepth, "dst")) goto cleanup; if (!copy_format_compatible(ctx, srcTexImage->InternalFormat, dstTexImage->InternalFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyImageSubData(internalFormat mismatch)"); goto cleanup; } for (i = 0; i < srcDepth; ++i) { int srcNewZ, dstNewZ; if (srcTexObj->Target == GL_TEXTURE_CUBE_MAP) { srcTexImage = srcTexObj->Image[i + srcZ][srcLevel]; srcNewZ = 0; } else { srcNewZ = srcZ + i; } if (dstTexObj->Target == GL_TEXTURE_CUBE_MAP) { dstTexImage = dstTexObj->Image[i + dstZ][dstLevel]; dstNewZ = 0; } else { dstNewZ = dstZ + i; } ctx->Driver.CopyImageSubData(ctx, srcTexImage, srcX, srcY, srcNewZ, dstTexImage, dstX, dstY, dstNewZ, srcWidth, srcHeight); } cleanup: _mesa_DeleteTextures(2, tmpTexNames); }
void GLAPIENTRY _mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) { GET_CURRENT_CONTEXT(ctx); struct gl_texture_image *srcTexImage, *dstTexImage; struct gl_renderbuffer *srcRenderbuffer, *dstRenderbuffer; mesa_format srcFormat, dstFormat; GLenum srcIntFormat, dstIntFormat; GLuint src_w, src_h, dst_w, dst_h; GLuint src_bw, src_bh, dst_bw, dst_bh; GLuint src_num_samples, dst_num_samples; int dstWidth, dstHeight, dstDepth; int i; if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, " "%u, %s, %d, %d, %d, %d, " "%d, %d, %d)\n", srcName, _mesa_enum_to_string(srcTarget), srcLevel, srcX, srcY, srcZ, dstName, _mesa_enum_to_string(dstTarget), dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth); if (!ctx->Extensions.ARB_copy_image) { _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyImageSubData(extension not available)"); return; } if (!prepare_target(ctx, srcName, srcTarget, srcLevel, srcZ, srcDepth, &srcTexImage, &srcRenderbuffer, &srcFormat, &srcIntFormat, &src_w, &src_h, &src_num_samples, "src")) return; if (!prepare_target(ctx, dstName, dstTarget, dstLevel, dstZ, srcDepth, &dstTexImage, &dstRenderbuffer, &dstFormat, &dstIntFormat, &dst_w, &dst_h, &dst_num_samples, "dst")) return; _mesa_get_format_block_size(srcFormat, &src_bw, &src_bh); /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core Profile * spec says: * * An INVALID_VALUE error is generated if the dimensions of either * subregion exceeds the boundaries of the corresponding image object, * or if the image format is compressed and the dimensions of the * subregion fail to meet the alignment constraints of the format. * * and Section 8.7 (Compressed Texture Images) says: * * An INVALID_OPERATION error is generated if any of the following * conditions occurs: * * * width is not a multiple of four, and width + xoffset is not * equal to the value of TEXTURE_WIDTH. * * height is not a multiple of four, and height + yoffset is not * equal to the value of TEXTURE_HEIGHT. * * so we take that to mean that you can copy the "last" block of a * compressed texture image even if it's smaller than the minimum block * dimensions. */ if ((srcX % src_bw != 0) || (srcY % src_bh != 0) || (srcWidth % src_bw != 0 && (srcX + srcWidth) != src_w) || (srcHeight % src_bh != 0 && (srcY + srcHeight) != src_h)) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(unaligned src rectangle)"); return; } _mesa_get_format_block_size(dstFormat, &dst_bw, &dst_bh); if ((dstX % dst_bw != 0) || (dstY % dst_bh != 0)) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(unaligned dst rectangle)"); return; } /* From the GL_ARB_copy_image spec: * * "The dimensions are always specified in texels, even for compressed * texture formats. But it should be noted that if only one of the * source and destination textures is compressed then the number of * texels touched in the compressed image will be a factor of the * block size larger than in the uncompressed image." * * So, if copying from compressed to uncompressed, the dest region is * shrunk by the src block size factor. If copying from uncompressed * to compressed, the dest region is grown by the dest block size factor. * Note that we're passed the _source_ width, height, depth and those * dimensions are never changed. */ dstWidth = srcWidth * dst_bw / src_bw; dstHeight = srcHeight * dst_bh / src_bh; dstDepth = srcDepth; if (!check_region_bounds(ctx, srcTarget, srcTexImage, srcRenderbuffer, srcX, srcY, srcZ, srcWidth, srcHeight, srcDepth, "src")) return; if (!check_region_bounds(ctx, dstTarget, dstTexImage, dstRenderbuffer, dstX, dstY, dstZ, dstWidth, dstHeight, dstDepth, "dst")) return; /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core Profile * spec says: * * An INVALID_OPERATION error is generated if either object is a texture * and the texture is not complete, if the source and destination internal * formats are not compatible, or if the number of samples do not match. */ if (!copy_format_compatible(ctx, srcIntFormat, dstIntFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyImageSubData(internalFormat mismatch)"); return; } if (src_num_samples != dst_num_samples) { _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyImageSubData(number of samples mismatch)"); return; } /* loop over 2D slices/faces/layers */ for (i = 0; i < srcDepth; ++i) { int newSrcZ = srcZ + i; int newDstZ = dstZ + i; if (srcTexImage && srcTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) { /* need to update srcTexImage pointer for the cube face */ assert(srcZ + i < MAX_FACES); srcTexImage = srcTexImage->TexObject->Image[srcZ + i][srcLevel]; assert(srcTexImage); newSrcZ = 0; } if (dstTexImage && dstTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) { /* need to update dstTexImage pointer for the cube face */ assert(dstZ + i < MAX_FACES); dstTexImage = dstTexImage->TexObject->Image[dstZ + i][dstLevel]; assert(dstTexImage); newDstZ = 0; } ctx->Driver.CopyImageSubData(ctx, srcTexImage, srcRenderbuffer, srcX, srcY, newSrcZ, dstTexImage, dstRenderbuffer, dstX, dstY, newDstZ, srcWidth, srcHeight); } }