2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 * Copyright (c) 2009 VMware, Inc.
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 * Code for glGetTexImage() and glGetCompressedTexImage().
35 #include "texcompress.h"
36 #include "texformat.h"
37 #include "texgetimage.h"
41 #if FEATURE_EXT_texture_sRGB
44 * Test if given texture image is an sRGB format.
47 is_srgb_teximage(const struct gl_texture_image *texImage)
49 switch (texImage->TexFormat->MesaFormat) {
50 case MESA_FORMAT_SRGB8:
51 case MESA_FORMAT_SRGBA8:
52 case MESA_FORMAT_SARGB8:
54 case MESA_FORMAT_SLA8:
55 case MESA_FORMAT_SRGB_DXT1:
56 case MESA_FORMAT_SRGBA_DXT1:
57 case MESA_FORMAT_SRGBA_DXT3:
58 case MESA_FORMAT_SRGBA_DXT5:
67 * Convert a float value from linear space to a
68 * non-linear sRGB value in [0, 255].
69 * Not terribly efficient.
72 linear_to_nonlinear(GLfloat cl)
74 /* can't have values outside [0, 1] */
76 if (cl < 0.0031308f) {
80 cs = (GLfloat)(1.055 * _mesa_pow(cl, 0.41666) - 0.055);
85 #endif /* FEATURE_EXT_texture_sRGB */
89 * Can the given type represent negative values?
91 static INLINE GLboolean
92 type_with_negative_values(GLenum type)
99 case GL_HALF_FLOAT_ARB:
108 * This is the software fallback for Driver.GetTexImage().
109 * All error checking will have been done before this routine is called.
112 _mesa_get_teximage(GLcontext *ctx, GLenum target, GLint level,
113 GLenum format, GLenum type, GLvoid *pixels,
114 struct gl_texture_object *texObj,
115 struct gl_texture_image *texImage)
117 const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
119 if (ctx->Pack.BufferObj->Name) {
120 /* Packing texture image into a PBO.
121 * Map the (potentially) VRAM-based buffer into our process space so
122 * we can write into it with the code below.
123 * A hardware driver might use a sophisticated blit to move the
124 * texture data to the PBO if the PBO is in VRAM along with the texture.
126 GLubyte *buf = (GLubyte *)
127 ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
128 GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);
130 /* buffer is already mapped - that's an error */
131 _mesa_error(ctx, GL_INVALID_OPERATION,"glGetTexImage(PBO is mapped)");
134 /* <pixels> was an offset into the PBO.
135 * Now make it a real, client-side pointer inside the mapped region.
137 pixels = ADD_POINTERS(buf, pixels);
145 const GLint width = texImage->Width;
146 const GLint height = texImage->Height;
147 const GLint depth = texImage->Depth;
149 for (img = 0; img < depth; img++) {
150 for (row = 0; row < height; row++) {
151 /* compute destination address in client memory */
152 GLvoid *dest = _mesa_image_address( dimensions, &ctx->Pack, pixels,
153 width, height, format, type,
157 if (format == GL_COLOR_INDEX) {
158 GLuint indexRow[MAX_WIDTH];
160 /* Can't use FetchTexel here because that returns RGBA */
161 if (texImage->TexFormat->IndexBits == 8) {
162 const GLubyte *src = (const GLubyte *) texImage->Data;
163 src += width * (img * texImage->Height + row);
164 for (col = 0; col < width; col++) {
165 indexRow[col] = src[col];
168 else if (texImage->TexFormat->IndexBits == 16) {
169 const GLushort *src = (const GLushort *) texImage->Data;
170 src += width * (img * texImage->Height + row);
171 for (col = 0; col < width; col++) {
172 indexRow[col] = src[col];
177 "Color index problem in _mesa_GetTexImage");
179 _mesa_pack_index_span(ctx, width, type, dest,
180 indexRow, &ctx->Pack,
181 0 /* no image transfer */);
183 else if (format == GL_DEPTH_COMPONENT) {
184 GLfloat depthRow[MAX_WIDTH];
186 for (col = 0; col < width; col++) {
187 (*texImage->FetchTexelf)(texImage, col, row, img,
190 _mesa_pack_depth_span(ctx, width, dest, type,
191 depthRow, &ctx->Pack);
193 else if (format == GL_DEPTH_STENCIL_EXT) {
194 /* XXX Note: we're bypassing texImage->FetchTexel()! */
195 const GLuint *src = (const GLuint *) texImage->Data;
196 src += width * row + width * height * img;
197 _mesa_memcpy(dest, src, width * sizeof(GLuint));
198 if (ctx->Pack.SwapBytes) {
199 _mesa_swap4((GLuint *) dest, width);
202 else if (format == GL_YCBCR_MESA) {
203 /* No pixel transfer */
204 const GLint rowstride = texImage->RowStride;
206 (const GLushort *) texImage->Data + row * rowstride,
207 width * sizeof(GLushort));
208 /* check for byte swapping */
209 if ((texImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR
210 && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) ||
211 (texImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR_REV
212 && type == GL_UNSIGNED_SHORT_8_8_MESA)) {
213 if (!ctx->Pack.SwapBytes)
214 _mesa_swap2((GLushort *) dest, width);
216 else if (ctx->Pack.SwapBytes) {
217 _mesa_swap2((GLushort *) dest, width);
220 #if FEATURE_EXT_texture_sRGB
221 else if (is_srgb_teximage(texImage)) {
222 /* special case this since need to backconvert values */
223 /* convert row to RGBA format */
224 GLfloat rgba[MAX_WIDTH][4];
226 GLbitfield transferOps = 0x0;
228 for (col = 0; col < width; col++) {
229 (*texImage->FetchTexelf)(texImage, col, row, img, rgba[col]);
230 if (texImage->_BaseFormat == GL_LUMINANCE) {
231 rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
232 rgba[col][GCOMP] = 0.0;
233 rgba[col][BCOMP] = 0.0;
235 else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
236 rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
237 rgba[col][GCOMP] = 0.0;
238 rgba[col][BCOMP] = 0.0;
240 else if (texImage->_BaseFormat == GL_RGB ||
241 texImage->_BaseFormat == GL_RGBA) {
242 rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
243 rgba[col][GCOMP] = linear_to_nonlinear(rgba[col][GCOMP]);
244 rgba[col][BCOMP] = linear_to_nonlinear(rgba[col][BCOMP]);
247 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
249 &ctx->Pack, transferOps);
251 #endif /* FEATURE_EXT_texture_sRGB */
253 /* general case: convert row to RGBA format */
254 GLfloat rgba[MAX_WIDTH][4];
256 GLbitfield transferOps = 0x0;
258 /* clamp does not apply to GetTexImage (final conversion)?
259 * Looks like we need clamp though when going from format
260 * containing negative values to unsigned format.
262 if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA)
263 transferOps |= IMAGE_CLAMP_BIT;
264 else if (!type_with_negative_values(type) &&
265 (texImage->TexFormat->DataType == GL_FLOAT ||
266 texImage->TexFormat->DataType == GL_SIGNED_NORMALIZED))
267 transferOps |= IMAGE_CLAMP_BIT;
269 for (col = 0; col < width; col++) {
270 (*texImage->FetchTexelf)(texImage, col, row, img, rgba[col]);
271 if (texImage->_BaseFormat == GL_ALPHA) {
272 rgba[col][RCOMP] = 0.0;
273 rgba[col][GCOMP] = 0.0;
274 rgba[col][BCOMP] = 0.0;
276 else if (texImage->_BaseFormat == GL_LUMINANCE) {
277 rgba[col][GCOMP] = 0.0;
278 rgba[col][BCOMP] = 0.0;
279 rgba[col][ACOMP] = 1.0;
281 else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
282 rgba[col][GCOMP] = 0.0;
283 rgba[col][BCOMP] = 0.0;
285 else if (texImage->_BaseFormat == GL_INTENSITY) {
286 rgba[col][GCOMP] = 0.0;
287 rgba[col][BCOMP] = 0.0;
288 rgba[col][ACOMP] = 1.0;
291 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
293 &ctx->Pack, transferOps);
299 if (ctx->Pack.BufferObj->Name) {
300 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
301 ctx->Pack.BufferObj);
308 * This is the software fallback for Driver.GetCompressedTexImage().
309 * All error checking will have been done before this routine is called.
312 _mesa_get_compressed_teximage(GLcontext *ctx, GLenum target, GLint level,
314 struct gl_texture_object *texObj,
315 struct gl_texture_image *texImage)
319 if (ctx->Pack.BufferObj->Name) {
320 /* pack texture image into a PBO */
322 if ((const GLubyte *) img + texImage->CompressedSize >
323 (const GLubyte *) ctx->Pack.BufferObj->Size) {
324 _mesa_error(ctx, GL_INVALID_OPERATION,
325 "glGetCompressedTexImage(invalid PBO access)");
328 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
330 ctx->Pack.BufferObj);
332 /* buffer is already mapped - that's an error */
333 _mesa_error(ctx, GL_INVALID_OPERATION,
334 "glGetCompressedTexImage(PBO is mapped)");
337 img = ADD_POINTERS(buf, img);
344 /* don't use texImage->CompressedSize since that may be padded out */
345 size = _mesa_compressed_texture_size(ctx, texImage->Width, texImage->Height,
347 texImage->TexFormat->MesaFormat);
349 /* just memcpy, no pixelstore or pixel transfer */
350 _mesa_memcpy(img, texImage->Data, size);
352 if (ctx->Pack.BufferObj->Name) {
353 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
354 ctx->Pack.BufferObj);