/** * When we're about to read pixel data out of a PBO (via glDrawPixels, * glTexImage, etc) or write data into a PBO (via glReadPixels, * glGetTexImage, etc) we call this function to check that we're not * going to read/write out of bounds. * * XXX This would also be a convenient time to check that the PBO isn't * currently mapped. Whoever calls this function should check for that. * Remember, we can't use a PBO when it's mapped! * * If we're not using a PBO, this is a no-op. * * \param width width of image to read/write * \param height height of image to read/write * \param depth depth of image to read/write * \param format format of image to read/write * \param type datatype of image to read/write * \param clientMemSize the maximum number of bytes to read/write * \param ptr the user-provided pointer/offset * \return GL_TRUE if the buffer access is OK, GL_FALSE if the access would * go out of bounds. */ GLboolean _mesa_validate_pbo_access(GLuint dimensions, const struct gl_pixelstore_attrib *pack, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei clientMemSize, const GLvoid *ptr) { const GLvoid *start, *end, *offset; const GLubyte *sizeAddr; /* buffer size, cast to a pointer */ /* If no PBO is bound, 'ptr' is a pointer to client memory containing 'clientMemSize' bytes. If a PBO is bound, 'ptr' is an offset into the bound PBO. In that case 'clientMemSize' is ignored: we just use the PBO's size. */ if (!_mesa_is_bufferobj(pack->BufferObj)) { offset = 0; sizeAddr = ((const GLubyte *) 0) + clientMemSize; } else { offset = ptr; sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size; /* The ARB_pixel_buffer_object spec says: * "INVALID_OPERATION is generated by ColorTable, ColorSubTable, * ConvolutionFilter2D, ConvolutionFilter1D, SeparableFilter2D, * TexImage1D, TexImage2D, TexImage3D, TexSubImage1D, * TexSubImage2D, TexSubImage3D, and DrawPixels if the current * PIXEL_UNPACK_BUFFER_BINDING_ARB value is non-zero and the data * parameter is not evenly divisible into the number of basic machine * units needed to store in memory a datum indicated by the type * parameter." */ if (type != GL_BITMAP && ((GLintptr)offset % _mesa_sizeof_packed_type(type))) return GL_FALSE; } if (sizeAddr == 0) /* no buffer! */ return GL_FALSE; /* get the offset to the first pixel we'll read/write */ start = _mesa_image_address(dimensions, pack, offset, width, height, format, type, 0, 0, 0); /* get the offset to just past the last pixel we'll read/write */ end = _mesa_image_address(dimensions, pack, offset, width, height, format, type, depth-1, height-1, width); if ((const GLubyte *) start > sizeAddr) { /* This will catch negative values / wrap-around */ return GL_FALSE; } if ((const GLubyte *) end > sizeAddr) { /* Image read/write goes beyond end of buffer */ return GL_FALSE; } /* OK! */ return GL_TRUE; }
/* * Read R, G, B, A, RGB, L, or LA pixels. */ static void read_rgba_pixels( struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels, const struct gl_pixelstore_attrib *packing ) { GLbitfield transferOps; bool dst_is_integer, dst_is_luminance, needs_rebase; int dst_stride, src_stride, rb_stride; uint32_t dst_format, src_format; GLubyte *dst, *map; mesa_format rb_format; bool needs_rgba; void *rgba, *src; bool src_is_uint = false; uint8_t rebase_swizzle[4]; struct gl_framebuffer *fb = ctx->ReadBuffer; struct gl_renderbuffer *rb = fb->_ColorReadBuffer; if (!rb) return; transferOps = get_readpixels_transfer_ops(ctx, rb->Format, format, type, GL_FALSE); /* Describe the dst format */ dst_is_integer = _mesa_is_enum_format_integer(format); dst_stride = _mesa_image_row_stride(packing, width, format, type); dst_format = _mesa_format_from_format_and_type(format, type); dst_is_luminance = format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA || format == GL_LUMINANCE_INTEGER_EXT || format == GL_LUMINANCE_ALPHA_INTEGER_EXT; dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, format, type, 0, 0); /* Map the source render buffer */ ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, &map, &rb_stride); if (!map) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); return; } rb_format = _mesa_get_srgb_format_linear(rb->Format); /* * Depending on the base formats involved in the conversion we might need to * rebase some values, so for these formats we compute a rebase swizzle. */ if (rb->_BaseFormat == GL_LUMINANCE || rb->_BaseFormat == GL_INTENSITY) { needs_rebase = true; rebase_swizzle[0] = MESA_FORMAT_SWIZZLE_X; rebase_swizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; rebase_swizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; rebase_swizzle[3] = MESA_FORMAT_SWIZZLE_ONE; } else if (rb->_BaseFormat == GL_LUMINANCE_ALPHA) { needs_rebase = true; rebase_swizzle[0] = MESA_FORMAT_SWIZZLE_X; rebase_swizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; rebase_swizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; rebase_swizzle[3] = MESA_FORMAT_SWIZZLE_W; } else if (_mesa_get_format_base_format(rb_format) != rb->_BaseFormat) { needs_rebase = _mesa_compute_rgba2base2rgba_component_mapping(rb->_BaseFormat, rebase_swizzle); } else { needs_rebase = false; } /* Since _mesa_format_convert does not handle transferOps we need to handle * them before we call the function. This requires to convert to RGBA float * first so we can call _mesa_apply_rgba_transfer_ops. If the dst format is * integer transferOps do not apply. * * Converting to luminance also requires converting to RGBA first, so we can * then compute luminance values as L=R+G+B. Notice that this is different * from GetTexImage, where we compute L=R. */ assert(!transferOps || (transferOps && !dst_is_integer)); needs_rgba = transferOps || dst_is_luminance; rgba = NULL; if (needs_rgba) { uint32_t rgba_format; int rgba_stride; bool need_convert; /* Convert to RGBA float or int/uint depending on the type of the src */ if (dst_is_integer) { src_is_uint = _mesa_is_format_unsigned(rb_format); if (src_is_uint) { rgba_format = RGBA32_UINT; rgba_stride = width * 4 * sizeof(GLuint); } else { rgba_format = RGBA32_INT; rgba_stride = width * 4 * sizeof(GLint); } } else { rgba_format = RGBA32_FLOAT; rgba_stride = width * 4 * sizeof(GLfloat); } /* If we are lucky and the dst format matches the RGBA format we need to * convert to, then we can convert directly into the dst buffer and avoid * the final conversion/copy from the rgba buffer to the dst buffer. */ if (dst_format == rgba_format) { need_convert = false; rgba = dst; } else { need_convert = true; rgba = malloc(height * rgba_stride); if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); goto done_unmap; } } /* Convert to RGBA now */ _mesa_format_convert(rgba, rgba_format, rgba_stride, map, rb_format, rb_stride, width, height, needs_rebase ? rebase_swizzle : NULL); /* Handle transfer ops if necessary */ if (transferOps) _mesa_apply_rgba_transfer_ops(ctx, transferOps, width * height, rgba); /* If we had to rebase, we have already taken care of that */ needs_rebase = false; /* If we were lucky and our RGBA conversion matches the dst format, then * we are done. */ if (!need_convert) goto done_swap; /* Otherwise, we need to convert from RGBA to dst next */ src = rgba; src_format = rgba_format; src_stride = rgba_stride; } else { /* No RGBA conversion needed, convert directly to dst */ src = map; src_format = rb_format; src_stride = rb_stride; } /* Do the conversion. * * If the dst format is Luminance, we need to do the conversion by computing * L=R+G+B values. */ if (!dst_is_luminance) { _mesa_format_convert(dst, dst_format, dst_stride, src, src_format, src_stride, width, height, needs_rebase ? rebase_swizzle : NULL); } else if (!dst_is_integer) { /* Compute float Luminance values from RGBA float */ int luminance_stride, luminance_bytes; void *luminance; uint32_t luminance_format; luminance_stride = width * sizeof(GL_FLOAT); if (format == GL_LUMINANCE_ALPHA) luminance_stride *= 2; luminance_bytes = height * luminance_stride; luminance = malloc(luminance_bytes); if (!luminance) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); free(rgba); goto done_unmap; } _mesa_pack_luminance_from_rgba_float(width * height, src, luminance, format, transferOps); /* Convert from Luminance float to dst (this will hadle type conversion * from float to the type of dst if necessary) */ luminance_format = _mesa_format_from_format_and_type(format, GL_FLOAT); _mesa_format_convert(dst, dst_format, dst_stride, luminance, luminance_format, luminance_stride, width, height, NULL); } else { _mesa_pack_luminance_from_rgba_integer(width * height, src, !src_is_uint, dst, format, type); } if (rgba) free(rgba); done_swap: /* Handle byte swapping if required */ if (packing->SwapBytes) { int components = _mesa_components_in_format(format); GLint swapSize = _mesa_sizeof_packed_type(type); if (swapSize == 2) _mesa_swap2((GLushort *) dst, width * height * components); else if (swapSize == 4) _mesa_swap4((GLuint *) dst, width * height * components); } done_unmap: ctx->Driver.UnmapRenderbuffer(ctx, rb); }
/** * When we're about to read pixel data out of a PBO (via glDrawPixels, * glTexImage, etc) or write data into a PBO (via glReadPixels, * glGetTexImage, etc) we call this function to check that we're not * going to read/write out of bounds. * * XXX This would also be a convenient time to check that the PBO isn't * currently mapped. Whoever calls this function should check for that. * Remember, we can't use a PBO when it's mapped! * * If we're not using a PBO, this is a no-op. * * \param width width of image to read/write * \param height height of image to read/write * \param depth depth of image to read/write * \param format format of image to read/write * \param type datatype of image to read/write * \param clientMemSize the maximum number of bytes to read/write * \param ptr the user-provided pointer/offset * \return GL_TRUE if the buffer access is OK, GL_FALSE if the access would * go out of bounds. */ GLboolean _mesa_validate_pbo_access(GLuint dimensions, const struct gl_pixelstore_attrib *pack, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei clientMemSize, const GLvoid *ptr) { /* unsigned, to detect overflow/wrap-around */ uintptr_t start, end, offset, size; /* If no PBO is bound, 'ptr' is a pointer to client memory containing 'clientMemSize' bytes. If a PBO is bound, 'ptr' is an offset into the bound PBO. In that case 'clientMemSize' is ignored: we just use the PBO's size. */ if (!_mesa_is_bufferobj(pack->BufferObj)) { offset = 0; size = (clientMemSize == INT_MAX) ? UINTPTR_MAX : clientMemSize; } else { offset = (uintptr_t)ptr; size = pack->BufferObj->Size; /* The ARB_pixel_buffer_object spec says: * "INVALID_OPERATION is generated by ColorTable, ColorSubTable, * ConvolutionFilter2D, ConvolutionFilter1D, SeparableFilter2D, * TexImage1D, TexImage2D, TexImage3D, TexSubImage1D, * TexSubImage2D, TexSubImage3D, and DrawPixels if the current * PIXEL_UNPACK_BUFFER_BINDING_ARB value is non-zero and the data * parameter is not evenly divisible into the number of basic machine * units needed to store in memory a datum indicated by the type * parameter." */ if (type != GL_BITMAP && (offset % _mesa_sizeof_packed_type(type))) return GL_FALSE; } if (size == 0) /* no buffer! */ return GL_FALSE; /* If the size of the image is zero then no pixels are accessed so we * don't need to check anything else. */ if (width == 0 || height == 0 || depth == 0) return GL_TRUE; /* get the offset to the first pixel we'll read/write */ start = _mesa_image_offset(dimensions, pack, width, height, format, type, 0, 0, 0); /* get the offset to just past the last pixel we'll read/write */ end = _mesa_image_offset(dimensions, pack, width, height, format, type, depth-1, height-1, width); start += offset; end += offset; if (start > size) { /* This will catch negative values / wrap-around */ return GL_FALSE; } if (end > size) { /* Image read/write goes beyond end of buffer */ return GL_FALSE; } /* OK! */ return GL_TRUE; }
/** * Do error checking for a glGetTexImage() call. * \return GL_TRUE if any error, GL_FALSE if no errors. */ static GLboolean getteximage_error_check(GLcontext *ctx, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels ) { struct gl_texture_object *texObj; struct gl_texture_image *texImage; const GLuint maxLevels = _mesa_max_texture_levels(ctx, target); GLenum baseFormat; if (maxLevels == 0) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target); return GL_TRUE; } if (level < 0 || level >= maxLevels) { _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" ); return GL_TRUE; } if (_mesa_sizeof_packed_type(type) <= 0) { _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" ); return GL_TRUE; } if (_mesa_components_in_format(format) <= 0 || format == GL_STENCIL_INDEX) { _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" ); return GL_TRUE; } if (!ctx->Extensions.EXT_paletted_texture && _mesa_is_index_format(format)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); return GL_TRUE; } if (!ctx->Extensions.ARB_depth_texture && _mesa_is_depth_format(format)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); return GL_TRUE; } if (!ctx->Extensions.MESA_ycbcr_texture && _mesa_is_ycbcr_format(format)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); return GL_TRUE; } if (!ctx->Extensions.EXT_packed_depth_stencil && _mesa_is_depthstencil_format(format)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); return GL_TRUE; } if (!ctx->Extensions.ATI_envmap_bumpmap && _mesa_is_dudv_format(format)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); return GL_TRUE; } texObj = _mesa_get_current_tex_object(ctx, target); if (!texObj || _mesa_is_proxy_texture(target)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)"); return GL_TRUE; } texImage = _mesa_select_tex_image(ctx, texObj, target, level); if (!texImage) { /* out of memory */ return GL_TRUE; } baseFormat = _mesa_get_format_base_format(texImage->TexFormat); /* Make sure the requested image format is compatible with the * texture's format. Note that a color index texture can be converted * to RGBA so that combo is allowed. */ if (_mesa_is_color_format(format) && !_mesa_is_color_format(baseFormat) && !_mesa_is_index_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } else if (_mesa_is_index_format(format) && !_mesa_is_index_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } else if (_mesa_is_depth_format(format) && !_mesa_is_depth_format(baseFormat) && !_mesa_is_depthstencil_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } else if (_mesa_is_ycbcr_format(format) && !_mesa_is_ycbcr_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } else if (_mesa_is_depthstencil_format(format) && !_mesa_is_depthstencil_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } else if (_mesa_is_dudv_format(format) && !_mesa_is_dudv_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { /* packing texture image into a PBO */ const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width, texImage->Height, texImage->Depth, format, type, pixels)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(out of bounds PBO write)"); return GL_TRUE; } /* PBO should not be mapped */ if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(PBO is mapped)"); return GL_TRUE; } } return GL_FALSE; }
/** * Get an uncompressed color texture image. */ static void get_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage, GLbitfield transferOps) { /* don't want to apply sRGB -> RGB conversion here so override the format */ const mesa_format texFormat = _mesa_get_srgb_format_linear(texImage->TexFormat); const GLuint width = texImage->Width; GLuint height = texImage->Height; GLuint depth = texImage->Depth; GLuint img; GLboolean dst_is_integer; uint32_t dst_format; int dst_stride; uint8_t rebaseSwizzle[4]; bool needsRebase; void *rgba = NULL; if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) { depth = height; height = 1; } /* Depending on the base format involved we may need to apply a rebase * transform (for example: if we download to a Luminance format we want * G=0 and B=0). */ if (texImage->_BaseFormat == GL_LUMINANCE || texImage->_BaseFormat == GL_INTENSITY) { needsRebase = true; rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X; rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_ONE; } else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { needsRebase = true; rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X; rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_W; // } else if (texImage->_BaseFormat != _mesa_get_format_base_format(texFormat)) { // needsRebase = // _mesa_compute_rgba2base2rgba_component_mapping(texImage->_BaseFormat, // rebaseSwizzle); } else { needsRebase = false; } /* Describe the dst format */ dst_is_integer = _mesa_is_enum_format_integer(format); dst_format = _mesa_format_from_format_and_type(format, type); dst_stride = _mesa_image_row_stride(&ctx->Pack, width, format, type); /* Since _mesa_format_convert does not handle transferOps we need to handle * them before we call the function. This requires to convert to RGBA float * first so we can call _mesa_apply_rgba_transfer_ops. If the dst format is * integer then transferOps do not apply. */ assert(!transferOps || (transferOps && !dst_is_integer)); (void) dst_is_integer; /* silence unused var warning */ for (img = 0; img < depth; img++) { GLubyte *srcMap; GLint rowstride; GLubyte *img_src; void *dest; void *src; int src_stride; uint32_t src_format; /* map src texture buffer */ ctx->Driver.MapTextureImage(ctx, texImage, img, 0, 0, width, height, GL_MAP_READ_BIT, &srcMap, &rowstride); if (!srcMap) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); goto done; } img_src = srcMap; dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, img, 0, 0); if (transferOps) { uint32_t rgba_format; int rgba_stride; bool need_convert = false; /* We will convert to RGBA float */ // rgba_format = RGBA32_FLOAT; rgba_stride = width * 4 * sizeof(GLfloat); /* If we are lucky and the dst format matches the RGBA format we need * to convert to, then we can convert directly into the dst buffer * and avoid the final conversion/copy from the rgba buffer to the dst * buffer. */ if (format == rgba_format) { rgba = dest; } else if (rgba == NULL) { /* Allocate the RGBA buffer only once */ need_convert = true; rgba = malloc(height * rgba_stride); if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); ctx->Driver.UnmapTextureImage(ctx, texImage, img); return; } } // _mesa_format_convert(rgba, rgba_format, rgba_stride, // img_src, texFormat, rowstride, // width, height, // needsRebase ? rebaseSwizzle : NULL); /* Handle transfer ops now */ _mesa_apply_rgba_transfer_ops(ctx, transferOps, width * height, rgba); /* If we had to rebase, we have already handled that */ needsRebase = false; /* If we were lucky and our RGBA conversion matches the dst format, then * we are done. */ if (!need_convert) goto do_swap; /* Otherwise, we need to convert from RGBA to dst next */ src = rgba; src_format = rgba_format; src_stride = rgba_stride; } else { /* No RGBA conversion needed, convert directly to dst */ src = img_src; src_format = texFormat; src_stride = rowstride; } /* Do the conversion to destination format */ // _mesa_format_convert(dest, dst_format, dst_stride, // src, src_format, src_stride, // width, height, // needsRebase ? rebaseSwizzle : NULL); do_swap: /* Handle byte swapping if required */ if (ctx->Pack.SwapBytes) { GLint swapSize = _mesa_sizeof_packed_type(type); if (swapSize == 2 || swapSize == 4) { int swapsPerPixel = _mesa_bytes_per_pixel(format, type) / swapSize; assert(_mesa_bytes_per_pixel(format, type) % swapSize == 0); if (swapSize == 2) _mesa_swap2((GLushort *) dest, width * height * swapsPerPixel); else if (swapSize == 4) _mesa_swap4((GLuint *) dest, width * height * swapsPerPixel); } } /* Unmap the src texture buffer */ ctx->Driver.UnmapTextureImage(ctx, texImage, img); } done: if (rgba) free(rgba); }
static GLboolean texstore_rgba(TEXSTORE_PARAMS) { void *tempImage = NULL, *tempRGBA = NULL; int srcRowStride, img; GLubyte *src, *dst; uint32_t srcMesaFormat; uint8_t rebaseSwizzle[4]; bool needRebase; bool transferOpsDone = false; /* We have to handle MESA_FORMAT_YCBCR manually because it is a special case * and _mesa_format_convert does not support it. In this case the we only * allow conversions between YCBCR formats and it is mostly a memcpy. */ if (dstFormat == MESA_FORMAT_YCBCR || dstFormat == MESA_FORMAT_YCBCR_REV) { return _mesa_texstore_ycbcr(ctx, dims, baseInternalFormat, dstFormat, dstRowStride, dstSlices, srcWidth, srcHeight, srcDepth, srcFormat, srcType, srcAddr, srcPacking); } /* We have to deal with GL_COLOR_INDEX manually because * _mesa_format_convert does not handle this format. So what we do here is * convert it to RGBA ubyte first and then convert from that to dst as usual. */ if (srcFormat == GL_COLOR_INDEX) { /* Notice that this will already handle byte swapping if necessary */ tempImage = _mesa_unpack_color_index_to_rgba_ubyte(ctx, dims, srcAddr, srcFormat, srcType, srcWidth, srcHeight, srcDepth, srcPacking, ctx->_ImageTransferState); if (!tempImage) return GL_FALSE; /* _mesa_unpack_color_index_to_rgba_ubyte has handled transferops * if needed. */ transferOpsDone = true; /* Now we only have to adjust our src info for a conversion from * the RGBA ubyte and then we continue as usual. */ srcAddr = tempImage; srcFormat = GL_RGBA; srcType = GL_UNSIGNED_BYTE; } else if (srcPacking->SwapBytes) { /* We have to handle byte-swapping scenarios before calling * _mesa_format_convert */ GLint swapSize = _mesa_sizeof_packed_type(srcType); if (swapSize == 2 || swapSize == 4) { int bytesPerPixel = _mesa_bytes_per_pixel(srcFormat, srcType); int swapsPerPixel = bytesPerPixel / swapSize; int elementCount = srcWidth * srcHeight * srcDepth; assert(bytesPerPixel % swapSize == 0); tempImage = malloc(elementCount * bytesPerPixel); if (!tempImage) return GL_FALSE; if (swapSize == 2) _mesa_swap2_copy(tempImage, (GLushort *) srcAddr, elementCount * swapsPerPixel); else _mesa_swap4_copy(tempImage, (GLuint *) srcAddr, elementCount * swapsPerPixel); srcAddr = tempImage; } } srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType); srcMesaFormat = _mesa_format_from_format_and_type(srcFormat, srcType); dstFormat = _mesa_get_srgb_format_linear(dstFormat); /* If we have transferOps then we need to convert to RGBA float first, then apply transferOps, then do the conversion to dst */ if (!transferOpsDone && _mesa_texstore_needs_transfer_ops(ctx, baseInternalFormat, dstFormat)) { /* Allocate RGBA float image */ int elementCount = srcWidth * srcHeight * srcDepth; tempRGBA = malloc(4 * elementCount * sizeof(float)); if (!tempRGBA) { free(tempImage); free(tempRGBA); return GL_FALSE; } /* Convert from src to RGBA float */ src = (GLubyte *) srcAddr; dst = (GLubyte *) tempRGBA; for (img = 0; img < srcDepth; img++) { _mesa_format_convert(dst, RGBA32_FLOAT, 4 * srcWidth * sizeof(float), src, srcMesaFormat, srcRowStride, srcWidth, srcHeight, NULL); src += srcHeight * srcRowStride; dst += srcHeight * 4 * srcWidth * sizeof(float); } /* Apply transferOps */ _mesa_apply_rgba_transfer_ops(ctx, ctx->_ImageTransferState, elementCount, (float(*)[4]) tempRGBA); /* Now we have to adjust our src info for a conversion from * the RGBA float image and then we continue as usual. */ srcAddr = tempRGBA; srcFormat = GL_RGBA; srcType = GL_FLOAT; srcRowStride = srcWidth * 4 * sizeof(float); srcMesaFormat = RGBA32_FLOAT; } src = (GLubyte *) _mesa_image_address(dims, srcPacking, srcAddr, srcWidth, srcHeight, srcFormat, srcType, 0, 0, 0); if (_mesa_get_format_base_format(dstFormat) != baseInternalFormat) { needRebase = _mesa_compute_rgba2base2rgba_component_mapping(baseInternalFormat, rebaseSwizzle); } else { needRebase = false; } for (img = 0; img < srcDepth; img++) { _mesa_format_convert(dstSlices[img], dstFormat, dstRowStride, src, srcMesaFormat, srcRowStride, srcWidth, srcHeight, needRebase ? rebaseSwizzle : NULL); src += srcHeight * srcRowStride; } free(tempImage); free(tempRGBA); return GL_TRUE; }
/** * Do error checking for a glGetTexImage() call. * \return GL_TRUE if any error, GL_FALSE if no errors. */ static GLboolean getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels ) { struct gl_texture_object *texObj; struct gl_texture_image *texImage; const GLint maxLevels = _mesa_max_texture_levels(ctx, target); GLenum baseFormat, err; if (maxLevels == 0) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target); return GL_TRUE; } if (level < 0 || level >= maxLevels) { _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" ); return GL_TRUE; } if (_mesa_sizeof_packed_type(type) <= 0) { _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" ); return GL_TRUE; } if (_mesa_components_in_format(format) <= 0 || format == GL_STENCIL_INDEX || format == GL_COLOR_INDEX) { _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" ); return GL_TRUE; } if (_mesa_is_depth_format(format)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); return GL_TRUE; } if (!ctx->Extensions.MESA_ycbcr_texture && _mesa_is_ycbcr_format(format)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); return GL_TRUE; } err = _mesa_error_check_format_and_type(ctx, format, type); if (err != GL_NO_ERROR) { _mesa_error(ctx, err, "glGetTexImage(format/type)"); return GL_TRUE; } texObj = _mesa_select_tex_object(ctx, target); if (!texObj || _mesa_is_proxy_texture(target)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)"); return GL_TRUE; } texImage = _mesa_select_tex_image(ctx, texObj, target, level); if (!texImage) { /* non-existant texture image */ return GL_TRUE; } baseFormat = _mesa_get_format_base_format(texImage->TexFormat); /* Make sure the requested image format is compatible with the * texture's format. */ if (_mesa_is_color_format(format) && !_mesa_is_color_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } else if (_mesa_is_depth_format(format) && !_mesa_is_depth_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } else if (_mesa_is_ycbcr_format(format) && !_mesa_is_ycbcr_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } return GL_FALSE; }