#include "enums.h"
#include "context.h"
#include "formats.h"
+#include "format_unpack.h"
#include "image.h"
+#include "mfeatures.h"
+#include "mtypes.h"
+#include "pack.h"
+#include "pbo.h"
#include "texcompress.h"
#include "texgetimage.h"
#include "teximage.h"
-#include "texstate.h"
-#if FEATURE_EXT_texture_sRGB
-
-/**
- * Convert a float value from linear space to a
- * non-linear sRGB value in [0, 255].
- * Not terribly efficient.
- */
-static INLINE GLfloat
-linear_to_nonlinear(GLfloat cl)
-{
- /* can't have values outside [0, 1] */
- GLfloat cs;
- if (cl < 0.0031308f) {
- cs = 12.92f * cl;
- }
- else {
- cs = (GLfloat)(1.055 * _mesa_pow(cl, 0.41666) - 0.055);
- }
- return cs;
-}
-
-#endif /* FEATURE_EXT_texture_sRGB */
-
-
/**
* Can the given type represent negative values?
*/
-static INLINE GLboolean
-type_with_negative_values(GLenum type)
+static inline GLboolean
+type_needs_clamping(GLenum type)
{
switch (type) {
case GL_BYTE:
case GL_INT:
case GL_FLOAT:
case GL_HALF_FLOAT_ARB:
- return GL_TRUE;
- default:
+ case GL_UNSIGNED_INT_10F_11F_11F_REV:
+ case GL_UNSIGNED_INT_5_9_9_9_REV:
return GL_FALSE;
+ default:
+ return GL_TRUE;
}
}
/**
- * glGetTexImage for color index pixels.
+ * glGetTexImage for depth/Z pixels.
*/
static void
-get_tex_color_index(GLcontext *ctx, GLuint dimensions,
- GLenum format, GLenum type, GLvoid *pixels,
- const struct gl_texture_image *texImage)
+get_tex_depth(struct gl_context *ctx, GLuint dimensions,
+ GLenum format, GLenum type, GLvoid *pixels,
+ struct gl_texture_image *texImage)
{
const GLint width = texImage->Width;
const GLint height = texImage->Height;
const GLint depth = texImage->Depth;
- const GLuint indexBits =
- _mesa_get_format_bits(texImage->TexFormat, GL_TEXTURE_INDEX_SIZE_EXT);
- const GLbitfield transferOps = 0x0;
- GLint img, row, col;
-
- for (img = 0; img < depth; img++) {
- for (row = 0; row < height; row++) {
- GLuint indexRow[MAX_WIDTH] = { 0 };
- void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
- width, height, format, type,
- img, row, 0);
- assert(dest);
+ GLint img, row;
+ GLfloat *depthRow = (GLfloat *) malloc(width * sizeof(GLfloat));
- if (indexBits == 8) {
- const GLubyte *src = (const GLubyte *) texImage->Data;
- src += width * (img * texImage->Height + row);
- for (col = 0; col < width; col++) {
- indexRow[col] = src[col];
- }
- }
- else if (indexBits == 16) {
- const GLushort *src = (const GLushort *) texImage->Data;
- src += width * (img * texImage->Height + row);
- for (col = 0; col < width; col++) {
- indexRow[col] = src[col];
- }
- }
- else {
- _mesa_problem(ctx, "Color index problem in _mesa_GetTexImage");
- }
- _mesa_pack_index_span(ctx, width, type, dest,
- indexRow, &ctx->Pack, transferOps);
- }
+ if (!depthRow) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
+ return;
}
-}
+ for (img = 0; img < depth; img++) {
+ GLubyte *srcMap;
+ GLint srcRowStride;
-/**
- * glGetTexImage for depth/Z pixels.
- */
-static void
-get_tex_depth(GLcontext *ctx, GLuint dimensions,
- GLenum format, GLenum type, GLvoid *pixels,
- const struct gl_texture_image *texImage)
-{
- const GLint width = texImage->Width;
- const GLint height = texImage->Height;
- const GLint depth = texImage->Depth;
- GLint img, row, col;
+ /* map src texture buffer */
+ ctx->Driver.MapTextureImage(ctx, texImage, img,
+ 0, 0, width, height, GL_MAP_READ_BIT,
+ &srcMap, &srcRowStride);
- for (img = 0; img < depth; img++) {
for (row = 0; row < height; row++) {
- GLfloat depthRow[MAX_WIDTH];
void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
width, height, format, type,
img, row, 0);
- assert(dest);
-
- for (col = 0; col < width; col++) {
- texImage->FetchTexelf(texImage, col, row, img, depthRow + col);
- }
+ const GLubyte *src = srcMap + row * srcRowStride;
+ _mesa_unpack_float_z_row(texImage->TexFormat, width, src, depthRow);
_mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack);
}
+
+ ctx->Driver.UnmapTextureImage(ctx, texImage, img);
}
+
+ free(depthRow);
}
* glGetTexImage for depth/stencil pixels.
*/
static void
-get_tex_depth_stencil(GLcontext *ctx, GLuint dimensions,
+get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions,
GLenum format, GLenum type, GLvoid *pixels,
- const struct gl_texture_image *texImage)
+ struct gl_texture_image *texImage)
{
const GLint width = texImage->Width;
const GLint height = texImage->Height;
const GLint depth = texImage->Depth;
- const GLuint *src = (const GLuint *) texImage->Data;
GLint img, row;
for (img = 0; img < depth; img++) {
+ GLubyte *srcMap;
+ GLint rowstride;
+
+ /* map src texture buffer */
+ ctx->Driver.MapTextureImage(ctx, texImage, img,
+ 0, 0, width, height, GL_MAP_READ_BIT,
+ &srcMap, &rowstride);
+
for (row = 0; row < height; row++) {
+ const GLubyte *src = srcMap + row * rowstride;
void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
width, height, format, type,
img, row, 0);
- _mesa_memcpy(dest, src, width * sizeof(GLuint));
+ /* XXX Z24_S8 vs. S8_Z24??? */
+ memcpy(dest, src, width * sizeof(GLuint));
if (ctx->Pack.SwapBytes) {
_mesa_swap4((GLuint *) dest, width);
}
-
- src += width * row + width * height * img;
}
+
+ ctx->Driver.UnmapTextureImage(ctx, texImage, img);
}
}
* glGetTexImage for YCbCr pixels.
*/
static void
-get_tex_ycbcr(GLcontext *ctx, GLuint dimensions,
+get_tex_ycbcr(struct gl_context *ctx, GLuint dimensions,
GLenum format, GLenum type, GLvoid *pixels,
- const struct gl_texture_image *texImage)
+ struct gl_texture_image *texImage)
{
const GLint width = texImage->Width;
const GLint height = texImage->Height;
const GLint depth = texImage->Depth;
- const GLint rowstride = texImage->RowStride;
- const GLushort *src = (const GLushort *) texImage->Data;
GLint img, row;
for (img = 0; img < depth; img++) {
+ GLubyte *srcMap;
+ GLint rowstride;
+
+ /* map src texture buffer */
+ ctx->Driver.MapTextureImage(ctx, texImage, img,
+ 0, 0, width, height, GL_MAP_READ_BIT,
+ &srcMap, &rowstride);
+
for (row = 0; row < height; row++) {
+ const GLubyte *src = srcMap + row * rowstride;
void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
width, height, format, type,
img, row, 0);
- _mesa_memcpy(dest, src, width * sizeof(GLushort));
+ memcpy(dest, src, width * sizeof(GLushort));
/* check for byte swapping */
if ((texImage->TexFormat == MESA_FORMAT_YCBCR
else if (ctx->Pack.SwapBytes) {
_mesa_swap2((GLushort *) dest, width);
}
-
- src += rowstride;
}
+
+ ctx->Driver.UnmapTextureImage(ctx, texImage, img);
}
}
/**
- * glGetTexImagefor sRGB pixels;
+ * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc).
+ * Compressed textures are handled here as well.
*/
static void
-get_tex_srgb(GLcontext *ctx, GLuint dimensions,
+get_tex_rgba(struct gl_context *ctx, GLuint dimensions,
GLenum format, GLenum type, GLvoid *pixels,
- const struct gl_texture_image *texImage)
+ struct gl_texture_image *texImage)
{
- const GLint width = texImage->Width;
- const GLint height = texImage->Height;
- const GLint depth = texImage->Depth;
- const GLbitfield transferOps = 0x0;
- GLint img, row;
+ /* don't want to apply sRGB -> RGB conversion here so override the format */
+ const gl_format texFormat = _mesa_get_srgb_format_linear(texImage->TexFormat);
+ const GLuint width = texImage->Width;
+ const GLuint height = texImage->Height;
+ const GLuint depth = texImage->Depth;
+ const GLenum dataType = _mesa_get_format_datatype(texFormat);
+ const GLenum baseFormat = _mesa_get_format_base_format(texFormat);
+ /* Normally, no pixel transfer ops are performed during glGetTexImage.
+ * The only possible exception is component clamping to [0,1].
+ */
+ GLbitfield transferOps = 0x0;
- for (img = 0; img < depth; img++) {
- for (row = 0; row < height; row++) {
- void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
- width, height, format, type,
- img, row, 0);
+ /* In general, clamping does not apply to glGetTexImage, except when
+ * the returned type of the image can't hold negative values.
+ */
+ if (type_needs_clamping(type)) {
+ /* the returned image type can't have negative values */
+ if (dataType == GL_FLOAT ||
+ dataType == GL_SIGNED_NORMALIZED ||
+ format == GL_LUMINANCE ||
+ format == GL_LUMINANCE_ALPHA) {
+ transferOps |= IMAGE_CLAMP_BIT;
+ }
+ }
- GLfloat rgba[MAX_WIDTH][4];
- GLint col;
+ if (_mesa_is_format_compressed(texFormat)) {
+ /* Decompress into temp buffer, then pack into user buffer */
+ GLfloat *tempImage, *srcRow;
+ GLuint row;
- /* convert row to RGBA format */
- for (col = 0; col < width; col++) {
- texImage->FetchTexelf(texImage, col, row, img, rgba[col]);
- if (texImage->_BaseFormat == GL_LUMINANCE) {
- rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
- rgba[col][GCOMP] = 0.0;
- rgba[col][BCOMP] = 0.0;
- }
- else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
- rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
- rgba[col][GCOMP] = 0.0;
- rgba[col][BCOMP] = 0.0;
- }
- else if (texImage->_BaseFormat == GL_RGB ||
- texImage->_BaseFormat == GL_RGBA) {
- rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
- rgba[col][GCOMP] = linear_to_nonlinear(rgba[col][GCOMP]);
- rgba[col][BCOMP] = linear_to_nonlinear(rgba[col][BCOMP]);
- }
- }
- _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
- format, type, dest,
- &ctx->Pack, transferOps);
+ tempImage = (GLfloat *) malloc(texImage->Width * texImage->Height *
+ texImage->Depth * 4 * sizeof(GLfloat));
+ if (!tempImage) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()");
+ return;
}
- }
-}
+ /* Decompress the texture image - results in 'tempImage' */
+ {
+ GLubyte *srcMap;
+ GLint srcRowStride;
+ GLuint bytes, bw, bh;
-/**
- * glGetTexImagefor RGBA, Luminance, etc. pixels.
- * This is the slow way since we use texture sampling.
- */
-static void
-get_tex_rgba(GLcontext *ctx, GLuint dimensions,
- GLenum format, GLenum type, GLvoid *pixels,
- const struct gl_texture_image *texImage)
-{
- const GLint width = texImage->Width;
- const GLint height = texImage->Height;
- const GLint depth = texImage->Depth;
- /* Normally, no pixel transfer ops are performed during glGetTexImage.
- * The only possible exception is component clamping to [0,1].
- */
- GLbitfield transferOps = 0x0;
- GLint img, row;
+ bytes = _mesa_get_format_bytes(texImage->TexFormat);
+ _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
- for (img = 0; img < depth; img++) {
+ ctx->Driver.MapTextureImage(ctx, texImage, 0,
+ 0, 0, width, height,
+ GL_MAP_READ_BIT,
+ &srcMap, &srcRowStride);
+
+ /* XXX This line is a bit of a hack to work around the
+ * mismatch of compressed row strides as returned by
+ * MapTextureImage() vs. what the texture decompression code
+ * uses. This will be fixed in the future.
+ */
+ srcRowStride = srcRowStride * bh / bytes;
+
+ _mesa_decompress_image(texFormat, width, height,
+ srcMap, srcRowStride, tempImage);
+
+ ctx->Driver.UnmapTextureImage(ctx, texImage, 0);
+ }
+
+ if (baseFormat == GL_LUMINANCE ||
+ baseFormat == GL_LUMINANCE_ALPHA) {
+ /* Set green and blue to zero since the pack function here will
+ * compute L=R+G+B.
+ */
+ GLuint i;
+ for (i = 0; i < width * height; i++) {
+ tempImage[i * 4 + GCOMP] = tempImage[i * 4 + BCOMP] = 0.0f;
+ }
+ }
+
+ srcRow = tempImage;
for (row = 0; row < height; row++) {
void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
width, height, format, type,
- img, row, 0);
- GLfloat rgba[MAX_WIDTH][4];
- GLint col;
- GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat);
+ 0, row, 0);
- /* clamp does not apply to GetTexImage (final conversion)?
- * Looks like we need clamp though when going from format
- * containing negative values to unsigned format.
- */
- if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) {
- transferOps |= IMAGE_CLAMP_BIT;
- }
- else if (!type_with_negative_values(type) &&
- (dataType == GL_FLOAT ||
- dataType == GL_SIGNED_NORMALIZED)) {
- transferOps |= IMAGE_CLAMP_BIT;
- }
+ _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) srcRow,
+ format, type, dest, &ctx->Pack, transferOps);
+ srcRow += width * 4;
+ }
+
+ free(tempImage);
+ }
+ else {
+ /* No decompression needed */
+ GLuint img, row;
+ GLfloat (*rgba)[4];
+
+ rgba = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat));
+ if (!rgba) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()");
+ return;
+ }
+
+ for (img = 0; img < depth; img++) {
+ GLubyte *srcMap;
+ GLint rowstride;
+
+ /* map src texture buffer */
+ ctx->Driver.MapTextureImage(ctx, texImage, img,
+ 0, 0, width, height, GL_MAP_READ_BIT,
+ &srcMap, &rowstride);
+
+ for (row = 0; row < height; row++) {
+ const GLubyte *src = srcMap + row * rowstride;
+ void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
+ width, height, format, type,
+ img, row, 0);
+
+ _mesa_unpack_rgba_row(texFormat, width, src, rgba);
- for (col = 0; col < width; col++) {
- texImage->FetchTexelf(texImage, col, row, img, rgba[col]);
if (texImage->_BaseFormat == GL_ALPHA) {
- rgba[col][RCOMP] = 0.0F;
- rgba[col][GCOMP] = 0.0F;
- rgba[col][BCOMP] = 0.0F;
+ GLint col;
+ for (col = 0; col < width; col++) {
+ rgba[col][RCOMP] = 0.0F;
+ rgba[col][GCOMP] = 0.0F;
+ rgba[col][BCOMP] = 0.0F;
+ }
}
else if (texImage->_BaseFormat == GL_LUMINANCE) {
- rgba[col][GCOMP] = 0.0F;
- rgba[col][BCOMP] = 0.0F;
- rgba[col][ACOMP] = 1.0F;
+ GLint col;
+ for (col = 0; col < width; col++) {
+ rgba[col][GCOMP] = 0.0F;
+ rgba[col][BCOMP] = 0.0F;
+ rgba[col][ACOMP] = 1.0F;
+ }
}
else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
- rgba[col][GCOMP] = 0.0F;
- rgba[col][BCOMP] = 0.0F;
+ GLint col;
+ for (col = 0; col < width; col++) {
+ rgba[col][GCOMP] = 0.0F;
+ rgba[col][BCOMP] = 0.0F;
+ }
}
else if (texImage->_BaseFormat == GL_INTENSITY) {
- rgba[col][GCOMP] = 0.0F;
- rgba[col][BCOMP] = 0.0F;
- rgba[col][ACOMP] = 1.0F;
+ GLint col;
+ for (col = 0; col < width; col++) {
+ rgba[col][GCOMP] = 0.0F;
+ rgba[col][BCOMP] = 0.0F;
+ rgba[col][ACOMP] = 1.0F;
+ }
}
+
+ _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
+ format, type, dest,
+ &ctx->Pack, transferOps);
}
- _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
- format, type, dest,
- &ctx->Pack, transferOps);
+
+ /* Unmap the src texture buffer */
+ ctx->Driver.UnmapTextureImage(ctx, texImage, img);
}
+
+ free(rgba);
}
}
* \return GL_TRUE if done, GL_FALSE otherwise
*/
static GLboolean
-get_tex_memcpy(GLcontext *ctx, GLenum format, GLenum type, GLvoid *pixels,
- const struct gl_texture_object *texObj,
- const struct gl_texture_image *texImage)
+get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type,
+ GLvoid *pixels,
+ struct gl_texture_image *texImage)
{
+ const GLenum target = texImage->TexObject->Target;
GLboolean memCopy = GL_FALSE;
- /* Texture image should have been mapped already */
- assert(texImage->Data);
-
/*
* Check if the src/dst formats are compatible.
* Also note that GL's pixel transfer ops don't apply to glGetTexImage()
* so we don't have to worry about those.
* XXX more format combinations could be supported here.
*/
- if ((texObj->Target == GL_TEXTURE_1D ||
- texObj->Target == GL_TEXTURE_2D ||
- texObj->Target == GL_TEXTURE_RECTANGLE ||
- (texObj->Target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
- texObj->Target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))) {
- if (texImage->TexFormat == MESA_FORMAT_ARGB8888 &&
+ if ((target == GL_TEXTURE_1D ||
+ target == GL_TEXTURE_2D ||
+ target == GL_TEXTURE_RECTANGLE ||
+ (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
+ target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))) {
+ if ((texImage->TexFormat == MESA_FORMAT_ARGB8888 ||
+ texImage->TexFormat == MESA_FORMAT_SARGB8) &&
format == GL_BGRA &&
- type == GL_UNSIGNED_BYTE &&
+ (type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT_8_8_8_8_REV) &&
!ctx->Pack.SwapBytes &&
_mesa_little_endian()) {
memCopy = GL_TRUE;
}
- else if (texImage->TexFormat == MESA_FORMAT_AL88 &&
+ else if ((texImage->TexFormat == MESA_FORMAT_AL88 ||
+ texImage->TexFormat == MESA_FORMAT_SLA8) &&
format == GL_LUMINANCE_ALPHA &&
type == GL_UNSIGNED_BYTE &&
!ctx->Pack.SwapBytes &&
_mesa_little_endian()) {
memCopy = GL_TRUE;
}
- else if (texImage->TexFormat == MESA_FORMAT_L8 &&
+ else if ((texImage->TexFormat == MESA_FORMAT_L8 ||
+ texImage->TexFormat == MESA_FORMAT_SL8) &&
format == GL_LUMINANCE &&
type == GL_UNSIGNED_BYTE) {
memCopy = GL_TRUE;
}
+ else if (texImage->TexFormat == MESA_FORMAT_L16 &&
+ format == GL_LUMINANCE &&
+ type == GL_UNSIGNED_SHORT) {
+ memCopy = GL_TRUE;
+ }
else if (texImage->TexFormat == MESA_FORMAT_A8 &&
format == GL_ALPHA &&
type == GL_UNSIGNED_BYTE) {
memCopy = GL_TRUE;
}
+ else if (texImage->TexFormat == MESA_FORMAT_A16 &&
+ format == GL_ALPHA &&
+ type == GL_UNSIGNED_SHORT) {
+ memCopy = GL_TRUE;
+ }
}
if (memCopy) {
texImage->Height, format, type, 0, 0);
const GLint dstRowStride =
_mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type);
- const GLubyte *src = texImage->Data;
- const GLint srcRowStride = texImage->RowStride * bpp;
- GLuint row;
+ GLubyte *src;
+ GLint srcRowStride;
+
+ /* map src texture buffer */
+ ctx->Driver.MapTextureImage(ctx, texImage, 0,
+ 0, 0, texImage->Width, texImage->Height,
+ GL_MAP_READ_BIT, &src, &srcRowStride);
if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) {
memcpy(dst, src, bytesPerRow * texImage->Height);
}
else {
+ GLuint row;
for (row = 0; row < texImage->Height; row++) {
memcpy(dst, src, bytesPerRow);
dst += dstRowStride;
src += srcRowStride;
}
}
+
+ /* unmap src texture buffer */
+ ctx->Driver.UnmapTextureImage(ctx, texImage, 0);
}
return memCopy;
/**
* This is the software fallback for Driver.GetTexImage().
* All error checking will have been done before this routine is called.
- * The texture image must be mapped.
+ * We'll call ctx->Driver.MapTextureImage() to access the data, then
+ * unmap with ctx->Driver.UnmapTextureImage().
*/
void
-_mesa_get_teximage(GLcontext *ctx, GLenum target, GLint level,
+_mesa_get_teximage(struct gl_context *ctx,
GLenum format, GLenum type, GLvoid *pixels,
- struct gl_texture_object *texObj,
struct gl_texture_image *texImage)
{
GLuint dimensions;
- /* If we get here, the texture image should be mapped */
- assert(texImage->Data);
-
- switch (target) {
+ switch (texImage->TexObject->Target) {
case GL_TEXTURE_1D:
dimensions = 1;
break;
dimensions = 2;
}
+ /* map dest buffer, if PBO */
if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
/* Packing texture image into a PBO.
* Map the (potentially) VRAM-based buffer into our process space so
* texture data to the PBO if the PBO is in VRAM along with the texture.
*/
GLubyte *buf = (GLubyte *)
- ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
- GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);
+ ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size,
+ GL_MAP_WRITE_BIT, ctx->Pack.BufferObj);
if (!buf) {
/* out of memory or other unexpected error */
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)");
pixels = ADD_POINTERS(buf, pixels);
}
- if (get_tex_memcpy(ctx, format, type, pixels, texObj, texImage)) {
+ if (get_tex_memcpy(ctx, format, type, pixels, texImage)) {
/* all done */
}
- else if (format == GL_COLOR_INDEX) {
- get_tex_color_index(ctx, dimensions, format, type, pixels, texImage);
- }
else if (format == GL_DEPTH_COMPONENT) {
get_tex_depth(ctx, dimensions, format, type, pixels, texImage);
}
else if (format == GL_YCBCR_MESA) {
get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage);
}
- else if (_mesa_get_format_color_encoding(texImage->TexFormat) == GL_SRGB) {
- get_tex_srgb(ctx, dimensions, format, type, pixels, texImage);
- }
else {
get_tex_rgba(ctx, dimensions, format, type, pixels, texImage);
}
if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
- ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
- ctx->Pack.BufferObj);
+ ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj);
}
}
* All error checking will have been done before this routine is called.
*/
void
-_mesa_get_compressed_teximage(GLcontext *ctx, GLenum target, GLint level,
+_mesa_get_compressed_teximage(struct gl_context *ctx, GLenum target, GLint level,
GLvoid *img,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage)
{
- const GLuint row_stride = _mesa_format_row_stride(texImage->TexFormat,
- texImage->Width);
- const GLuint row_stride_stored = _mesa_format_row_stride(texImage->TexFormat,
- texImage->RowStride);
+ const GLuint row_stride =
+ _mesa_format_row_stride(texImage->TexFormat, texImage->Width);
GLuint i;
+ GLubyte *src;
+ GLint srcRowStride;
if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
/* pack texture image into a PBO */
GLubyte *buf = (GLubyte *)
- ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
- GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);
+ ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size,
+ GL_MAP_WRITE_BIT, ctx->Pack.BufferObj);
if (!buf) {
/* out of memory or other unexpected error */
_mesa_error(ctx, GL_OUT_OF_MEMORY,
img = ADD_POINTERS(buf, img);
}
+ /* map src texture buffer */
+ ctx->Driver.MapTextureImage(ctx, texImage, 0,
+ 0, 0, texImage->Width, texImage->Height,
+ GL_MAP_READ_BIT, &src, &srcRowStride);
+
/* no pixelstore or pixel transfer, but respect stride */
- if (row_stride == row_stride_stored) {
+ if (row_stride == srcRowStride) {
const GLuint size = _mesa_format_image_size(texImage->TexFormat,
texImage->Width,
texImage->Height,
texImage->Depth);
- _mesa_memcpy(img, texImage->Data, size);
+ memcpy(img, src, size);
}
else {
GLuint bw, bh;
_mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) {
memcpy((GLubyte *)img + i * row_stride,
- (GLubyte *)texImage->Data + i * row_stride_stored,
+ (GLubyte *)src + i * srcRowStride,
row_stride);
}
}
+ ctx->Driver.UnmapTextureImage(ctx, texImage, 0);
+
if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
- ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
- ctx->Pack.BufferObj);
+ ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj);
}
}
* \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 )
+getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level,
+ GLenum format, GLenum type, GLsizei clientMemSize,
+ GLvoid *pixels )
{
struct gl_texture_object *texObj;
struct gl_texture_image *texImage;
- const GLuint maxLevels = _mesa_max_texture_levels(ctx, target);
+ const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
+ const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
GLenum baseFormat;
if (maxLevels == 0) {
}
if (_mesa_components_in_format(format) <= 0 ||
- format == GL_STENCIL_INDEX) {
+ format == GL_STENCIL_INDEX ||
+ format == GL_COLOR_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;
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.
+ * texture's format.
*/
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_is_color_format(baseFormat)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
return GL_TRUE;
}
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)) {
+ if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
+ texImage->Height, texImage->Depth,
+ format, type, clientMemSize, pixels)) {
+ if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetTexImage(out of bounds PBO write)");
- return GL_TRUE;
+ "glGetTexImage(out of bounds PBO access)");
+ } else {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetnTexImageARB(out of bounds access:"
+ " bufSize (%d) is too small)", clientMemSize);
}
+ return GL_TRUE;
+ }
+ if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
/* PBO should not be mapped */
if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
* \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 GLAPIENTRY
-_mesa_GetTexImage( GLenum target, GLint level, GLenum format,
- GLenum type, GLvoid *pixels )
+_mesa_GetnTexImageARB( GLenum target, GLint level, GLenum format,
+ GLenum type, GLsizei bufSize, GLvoid *pixels )
{
struct gl_texture_object *texObj;
struct gl_texture_image *texImage;
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
- if (getteximage_error_check(ctx, target, level, format, type, pixels)) {
+ if (getteximage_error_check(ctx, target, level, format, type,
+ bufSize, pixels)) {
return;
}
_mesa_lock_texture(ctx, texObj);
{
- ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels,
- texObj, texImage);
+ ctx->Driver.GetTexImage(ctx, format, type, pixels, texImage);
}
_mesa_unlock_texture(ctx, texObj);
}
+void GLAPIENTRY
+_mesa_GetTexImage( GLenum target, GLint level, GLenum format,
+ GLenum type, GLvoid *pixels )
+{
+ _mesa_GetnTexImageARB(target, level, format, type, INT_MAX, pixels);
+}
+
/**
* Do error checking for a glGetCompressedTexImage() call.
* \return GL_TRUE if any error, GL_FALSE if no errors.
*/
static GLboolean
-getcompressedteximage_error_check(GLcontext *ctx, GLenum target, GLint level,
- GLvoid *img)
+getcompressedteximage_error_check(struct gl_context *ctx, GLenum target,
+ GLint level, GLsizei clientMemSize, GLvoid *img)
{
struct gl_texture_object *texObj;
struct gl_texture_image *texImage;
- const GLuint maxLevels = _mesa_max_texture_levels(ctx, target);
+ const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
+ GLuint compressedSize;
if (maxLevels == 0) {
_mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)",
return GL_TRUE;
}
- if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
- GLuint compressedSize;
+ compressedSize = _mesa_format_image_size(texImage->TexFormat,
+ texImage->Width,
+ texImage->Height,
+ texImage->Depth);
- /* make sure PBO is not mapped */
- if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
+ if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
+ /* do bounds checking on writing to client memory */
+ if (clientMemSize < compressedSize) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetCompressedTexImage(PBO is mapped)");
- return GL_TRUE;
+ "glGetnCompressedTexImageARB(out of bounds access:"
+ " bufSize (%d) is too small)", clientMemSize);
}
-
- compressedSize = _mesa_format_image_size(texImage->TexFormat,
- texImage->Width,
- texImage->Height,
- texImage->Depth);
-
+ } else {
/* do bounds checking on PBO write */
if ((const GLubyte *) img + compressedSize >
(const GLubyte *) ctx->Pack.BufferObj->Size) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetCompressedTexImage(out of bounds PBO write)");
+ "glGetCompressedTexImage(out of bounds PBO access)");
+ return GL_TRUE;
+ }
+
+ /* make sure PBO is not mapped */
+ if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetCompressedTexImage(PBO is mapped)");
return GL_TRUE;
}
}
void GLAPIENTRY
-_mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
+_mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize,
+ GLvoid *img)
{
struct gl_texture_object *texObj;
struct gl_texture_image *texImage;
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
- if (getcompressedteximage_error_check(ctx, target, level, img)) {
+ if (getcompressedteximage_error_check(ctx, target, level, bufSize, img)) {
return;
}
- if (_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) {
+ if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) {
/* not an error, do nothing */
return;
}
}
_mesa_unlock_texture(ctx, texObj);
}
+
+void GLAPIENTRY
+_mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
+{
+ _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img);
+}