/** * Teximage storage routine for when a simple memcpy will do. * No pixel transfer operations or special texel encodings allowed. * 1D, 2D and 3D images supported. */ static void memcpy_texture(struct gl_context *ctx, GLuint dimensions, mesa_format dstFormat, GLint dstRowStride, GLubyte **dstSlices, GLint srcWidth, GLint srcHeight, GLint srcDepth, GLenum srcFormat, GLenum srcType, const GLvoid *srcAddr, const struct gl_pixelstore_attrib *srcPacking) { const GLint srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType); const GLint srcImageStride = _mesa_image_image_stride(srcPacking, srcWidth, srcHeight, srcFormat, srcType); const GLubyte *srcImage = (const GLubyte *) _mesa_image_address(dimensions, srcPacking, srcAddr, srcWidth, srcHeight, srcFormat, srcType, 0, 0, 0); const GLuint texelBytes = _mesa_get_format_bytes(dstFormat); const GLint bytesPerRow = srcWidth * texelBytes; if (dstRowStride == srcRowStride && dstRowStride == bytesPerRow) { /* memcpy image by image */ GLint img; for (img = 0; img < srcDepth; img++) { GLubyte *dstImage = dstSlices[img]; memcpy(dstImage, srcImage, bytesPerRow * srcHeight); srcImage += srcImageStride; } } else { /* memcpy row by row */ GLint img, row; for (img = 0; img < srcDepth; img++) { const GLubyte *srcRow = srcImage; GLubyte *dstRow = dstSlices[img]; for (row = 0; row < srcHeight; row++) { memcpy(dstRow, srcRow, bytesPerRow); dstRow += dstRowStride; srcRow += srcRowStride; } srcImage += srcImageStride; } } }
/** * Get texture image. * * \param texture texture name. * \param level image level. * \param format pixel data format for returned image. * \param type pixel data type for returned image. * \param bufSize size of the pixels data buffer. * \param pixels returned pixel data. */ void glGetTextureImage(GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid *pixels) { struct gl_texture_object *texObj; struct gl_texture_image *texImage; int i; GLint image_stride; GLenum err; GET_CURRENT_CONTEXT(ctx); /* * This has been moved here because a format/type mismatch can cause a NULL * texImage object, which in turn causes the mismatch error to be * ignored. */ err = _mesa_error_check_format_and_type(ctx, format, type); if (err != GL_NO_ERROR) { _mesa_error(ctx, err, "glGetTextureImage(format/type)"); return; } texObj = _mesa_lookup_texture_err(ctx, texture, "glGetTextureImage"); if (!texObj) return; /* * Legal target checking has been moved here to prevent exiting with a NULL * texImage object. */ if (!legal_getteximage_target(ctx, texObj->Target, true)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTextureImage(target=%s)", _mesa_lookup_enum_by_nr(texObj->Target)); return; } /* Must handle special case GL_TEXTURE_CUBE_MAP. */ if (texObj->Target == GL_TEXTURE_CUBE_MAP) { /* Make sure the texture object is a proper cube. * (See texturesubimage in teximage.c for details on why this check is * performed.) */ if (!_mesa_cube_level_complete(texObj, level)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTextureImage(cube map incomplete)"); return; } /* Copy each face. */ for (i = 0; i < 6; ++i) { texImage = texObj->Image[i][level]; assert(texImage); _mesa_get_texture_image(ctx, texObj, texImage, texObj->Target, level, format, type, bufSize, pixels, true); image_stride = _mesa_image_image_stride(&ctx->Pack, texImage->Width, texImage->Height, format, type); pixels = (GLubyte *) pixels + image_stride; bufSize -= image_stride; } } else { texImage = _mesa_select_tex_image(texObj, texObj->Target, level); if (!texImage) return; _mesa_get_texture_image(ctx, texObj, texImage, texObj->Target, level, format, type, bufSize, pixels, true); } }
/** * Helper function for storing 1D, 2D, 3D whole and subimages into texture * memory. * The source of the image data may be user memory or a PBO. In the later * case, we'll map the PBO, copy from it, then unmap it. */ static void store_texsubimage(struct gl_context *ctx, struct gl_texture_image *texImage, GLint xoffset, GLint yoffset, GLint zoffset, GLint width, GLint height, GLint depth, GLenum format, GLenum type, const GLvoid *pixels, const struct gl_pixelstore_attrib *packing, const char *caller) { const GLbitfield mapMode = get_read_write_mode(format, texImage->TexFormat); const GLenum target = texImage->TexObject->Target; GLboolean success = GL_FALSE; GLuint dims, slice, numSlices = 1, sliceOffset = 0; GLint srcImageStride = 0; const GLubyte *src; assert(xoffset + width <= texImage->Width); assert(yoffset + height <= texImage->Height); assert(zoffset + depth <= texImage->Depth); switch (target) { case GL_TEXTURE_1D: dims = 1; break; case GL_TEXTURE_2D_ARRAY: case GL_TEXTURE_CUBE_MAP_ARRAY: case GL_TEXTURE_3D: dims = 3; break; default: dims = 2; } /* get pointer to src pixels (may be in a pbo which we'll map here) */ src = (const GLubyte *) _mesa_validate_pbo_teximage(ctx, dims, width, height, depth, format, type, pixels, packing, caller); if (!src) return; /* compute slice info (and do some sanity checks) */ switch (target) { case GL_TEXTURE_2D: case GL_TEXTURE_RECTANGLE: case GL_TEXTURE_CUBE_MAP: case GL_TEXTURE_EXTERNAL_OES: /* one image slice, nothing special needs to be done */ break; case GL_TEXTURE_1D: assert(height == 1); assert(depth == 1); assert(yoffset == 0); assert(zoffset == 0); break; case GL_TEXTURE_1D_ARRAY: assert(depth == 1); assert(zoffset == 0); numSlices = height; sliceOffset = yoffset; height = 1; yoffset = 0; srcImageStride = _mesa_image_row_stride(packing, width, format, type); break; case GL_TEXTURE_2D_ARRAY: numSlices = depth; sliceOffset = zoffset; depth = 1; zoffset = 0; srcImageStride = _mesa_image_image_stride(packing, width, height, format, type); break; case GL_TEXTURE_3D: /* we'll store 3D images as a series of slices */ numSlices = depth; sliceOffset = zoffset; srcImageStride = _mesa_image_image_stride(packing, width, height, format, type); break; case GL_TEXTURE_CUBE_MAP_ARRAY: numSlices = depth; sliceOffset = zoffset; srcImageStride = _mesa_image_image_stride(packing, width, height, format, type); break; default: _mesa_warning(ctx, "Unexpected target 0x%x in store_texsubimage()", target); return; } assert(numSlices == 1 || srcImageStride != 0); for (slice = 0; slice < numSlices; slice++) { GLubyte *dstMap; GLint dstRowStride; ctx->Driver.MapTextureImage(ctx, texImage, slice + sliceOffset, xoffset, yoffset, width, height, mapMode, &dstMap, &dstRowStride); if (dstMap) { /* Note: we're only storing a 2D (or 1D) slice at a time but we need * to pass the right 'dims' value so that GL_UNPACK_SKIP_IMAGES is * used for 3D images. */ success = _mesa_texstore(ctx, dims, texImage->_BaseFormat, texImage->TexFormat, dstRowStride, &dstMap, width, height, 1, /* w, h, d */ format, type, src, packing); ctx->Driver.UnmapTextureImage(ctx, texImage, slice + sliceOffset); } src += srcImageStride; if (!success) break; } if (!success) _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller); _mesa_unmap_teximage_pbo(ctx, packing); }