From 34f1ddbb272a5ad55f56d54e2f861da6360db04f Mon Sep 17 00:00:00 2001 From: marha Date: Mon, 2 May 2011 06:32:47 +0000 Subject: mesa git update 1 May 2011 --- mesalib/src/mesa/main/get.c | 2 +- mesalib/src/mesa/main/pack.c | 10389 +++++++++---------- mesalib/src/mesa/main/shaderapi.c | 3884 ++++--- mesalib/src/mesa/main/texcompress_s3tc.c | 1132 +- mesalib/src/mesa/program/ir_to_mesa.cpp | 5 +- mesalib/src/mesa/program/register_allocate.c | 1054 +- mesalib/src/mesa/program/register_allocate.h | 143 +- .../src/mesa/state_tracker/st_atom_pixeltransfer.c | 10 - mesalib/src/mesa/state_tracker/st_cb_drawpixels.c | 3084 +++--- 9 files changed, 9842 insertions(+), 9861 deletions(-) (limited to 'mesalib') diff --git a/mesalib/src/mesa/main/get.c b/mesalib/src/mesa/main/get.c index e933bbe0f..0492e1585 100644 --- a/mesalib/src/mesa/main/get.c +++ b/mesalib/src/mesa/main/get.c @@ -1163,7 +1163,7 @@ static const struct value_desc values[] = { /* GL_EXT_provoking_vertex */ { GL_PROVOKING_VERTEX_EXT, - CONTEXT_BOOL(Light.ProvokingVertex), extra_EXT_provoking_vertex }, + CONTEXT_ENUM(Light.ProvokingVertex), extra_EXT_provoking_vertex }, { GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT, CONTEXT_BOOL(Const.QuadsFollowProvokingVertexConvention), extra_EXT_provoking_vertex }, diff --git a/mesalib/src/mesa/main/pack.c b/mesalib/src/mesa/main/pack.c index e6734bbbc..d6470e351 100644 --- a/mesalib/src/mesa/main/pack.c +++ b/mesalib/src/mesa/main/pack.c @@ -1,5196 +1,5193 @@ -/* - * Mesa 3-D graphics library - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * Copyright (C) 2009-2010 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THEA AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -/** - * \file pack.c - * Image and pixel span packing and unpacking. - */ - - -#include "glheader.h" -#include "colormac.h" -#include "enums.h" -#include "image.h" -#include "imports.h" -#include "mtypes.h" -#include "pack.h" -#include "pixeltransfer.h" -#include "imports.h" -#include "../../gallium/auxiliary/util/u_format_rgb9e5.h" -#include "../../gallium/auxiliary/util/u_format_r11g11b10f.h" - - -/** - * NOTE: - * Normally, BYTE_TO_FLOAT(0) returns 0.00392 That causes problems when - * we later convert the float to a packed integer value (such as for - * GL_RGB5_A1) because we'll wind up with a non-zero value. - * - * We redefine the macros here so zero is handled correctly. - */ -#undef BYTE_TO_FLOAT -#define BYTE_TO_FLOAT(B) ((B) == 0 ? 0.0F : ((2.0F * (B) + 1.0F) * (1.0F/255.0F))) - -#undef SHORT_TO_FLOAT -#define SHORT_TO_FLOAT(S) ((S) == 0 ? 0.0F : ((2.0F * (S) + 1.0F) * (1.0F/65535.0F))) - - - -/** Compute ceiling of integer quotient of A divided by B. */ -#define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 ) - - -/** - * Flip the 8 bits in each byte of the given array. - * - * \param p array. - * \param n number of bytes. - * - * \todo try this trick to flip bytes someday: - * \code - * v = ((v & 0x55555555) << 1) | ((v >> 1) & 0x55555555); - * v = ((v & 0x33333333) << 2) | ((v >> 2) & 0x33333333); - * v = ((v & 0x0f0f0f0f) << 4) | ((v >> 4) & 0x0f0f0f0f); - * \endcode - */ -static void -flip_bytes( GLubyte *p, GLuint n ) -{ - GLuint i, a, b; - for (i = 0; i < n; i++) { - b = (GLuint) p[i]; /* words are often faster than bytes */ - a = ((b & 0x01) << 7) | - ((b & 0x02) << 5) | - ((b & 0x04) << 3) | - ((b & 0x08) << 1) | - ((b & 0x10) >> 1) | - ((b & 0x20) >> 3) | - ((b & 0x40) >> 5) | - ((b & 0x80) >> 7); - p[i] = (GLubyte) a; - } -} - - - -/* - * Unpack a 32x32 pixel polygon stipple from user memory using the - * current pixel unpack settings. - */ -void -_mesa_unpack_polygon_stipple( const GLubyte *pattern, GLuint dest[32], - const struct gl_pixelstore_attrib *unpacking ) -{ - GLubyte *ptrn = (GLubyte *) _mesa_unpack_bitmap(32, 32, pattern, unpacking); - if (ptrn) { - /* Convert pattern from GLubytes to GLuints and handle big/little - * endian differences - */ - GLubyte *p = ptrn; - GLint i; - for (i = 0; i < 32; i++) { - dest[i] = (p[0] << 24) - | (p[1] << 16) - | (p[2] << 8) - | (p[3] ); - p += 4; - } - free(ptrn); - } -} - - -/* - * Pack polygon stipple into user memory given current pixel packing - * settings. - */ -void -_mesa_pack_polygon_stipple( const GLuint pattern[32], GLubyte *dest, - const struct gl_pixelstore_attrib *packing ) -{ - /* Convert pattern from GLuints to GLubytes to handle big/little - * endian differences. - */ - GLubyte ptrn[32*4]; - GLint i; - for (i = 0; i < 32; i++) { - ptrn[i * 4 + 0] = (GLubyte) ((pattern[i] >> 24) & 0xff); - ptrn[i * 4 + 1] = (GLubyte) ((pattern[i] >> 16) & 0xff); - ptrn[i * 4 + 2] = (GLubyte) ((pattern[i] >> 8 ) & 0xff); - ptrn[i * 4 + 3] = (GLubyte) ((pattern[i] ) & 0xff); - } - - _mesa_pack_bitmap(32, 32, ptrn, dest, packing); -} - - -/* - * Unpack bitmap data. Resulting data will be in most-significant-bit-first - * order with row alignment = 1 byte. - */ -GLvoid * -_mesa_unpack_bitmap( GLint width, GLint height, const GLubyte *pixels, - const struct gl_pixelstore_attrib *packing ) -{ - GLint bytes, row, width_in_bytes; - GLubyte *buffer, *dst; - - if (!pixels) - return NULL; - - /* Alloc dest storage */ - bytes = ((width + 7) / 8 * height); - buffer = (GLubyte *) malloc( bytes ); - if (!buffer) - return NULL; - - width_in_bytes = CEILING( width, 8 ); - dst = buffer; - for (row = 0; row < height; row++) { - const GLubyte *src = (const GLubyte *) - _mesa_image_address2d(packing, pixels, width, height, - GL_COLOR_INDEX, GL_BITMAP, row, 0); - if (!src) { - free(buffer); - return NULL; - } - - if ((packing->SkipPixels & 7) == 0) { - memcpy( dst, src, width_in_bytes ); - if (packing->LsbFirst) { - flip_bytes( dst, width_in_bytes ); - } - } - else { - /* handling SkipPixels is a bit tricky (no pun intended!) */ - GLint i; - if (packing->LsbFirst) { - GLubyte srcMask = 1 << (packing->SkipPixels & 0x7); - GLubyte dstMask = 128; - const GLubyte *s = src; - GLubyte *d = dst; - *d = 0; - for (i = 0; i < width; i++) { - if (*s & srcMask) { - *d |= dstMask; - } - if (srcMask == 128) { - srcMask = 1; - s++; - } - else { - srcMask = srcMask << 1; - } - if (dstMask == 1) { - dstMask = 128; - d++; - *d = 0; - } - else { - dstMask = dstMask >> 1; - } - } - } - else { - GLubyte srcMask = 128 >> (packing->SkipPixels & 0x7); - GLubyte dstMask = 128; - const GLubyte *s = src; - GLubyte *d = dst; - *d = 0; - for (i = 0; i < width; i++) { - if (*s & srcMask) { - *d |= dstMask; - } - if (srcMask == 1) { - srcMask = 128; - s++; - } - else { - srcMask = srcMask >> 1; - } - if (dstMask == 1) { - dstMask = 128; - d++; - *d = 0; - } - else { - dstMask = dstMask >> 1; - } - } - } - } - dst += width_in_bytes; - } - - return buffer; -} - - -/* - * Pack bitmap data. - */ -void -_mesa_pack_bitmap( GLint width, GLint height, const GLubyte *source, - GLubyte *dest, const struct gl_pixelstore_attrib *packing ) -{ - GLint row, width_in_bytes; - const GLubyte *src; - - if (!source) - return; - - width_in_bytes = CEILING( width, 8 ); - src = source; - for (row = 0; row < height; row++) { - GLubyte *dst = (GLubyte *) _mesa_image_address2d(packing, dest, - width, height, GL_COLOR_INDEX, GL_BITMAP, row, 0); - if (!dst) - return; - - if ((packing->SkipPixels & 7) == 0) { - memcpy( dst, src, width_in_bytes ); - if (packing->LsbFirst) { - flip_bytes( dst, width_in_bytes ); - } - } - else { - /* handling SkipPixels is a bit tricky (no pun intended!) */ - GLint i; - if (packing->LsbFirst) { - GLubyte srcMask = 128; - GLubyte dstMask = 1 << (packing->SkipPixels & 0x7); - const GLubyte *s = src; - GLubyte *d = dst; - *d = 0; - for (i = 0; i < width; i++) { - if (*s & srcMask) { - *d |= dstMask; - } - if (srcMask == 1) { - srcMask = 128; - s++; - } - else { - srcMask = srcMask >> 1; - } - if (dstMask == 128) { - dstMask = 1; - d++; - *d = 0; - } - else { - dstMask = dstMask << 1; - } - } - } - else { - GLubyte srcMask = 128; - GLubyte dstMask = 128 >> (packing->SkipPixels & 0x7); - const GLubyte *s = src; - GLubyte *d = dst; - *d = 0; - for (i = 0; i < width; i++) { - if (*s & srcMask) { - *d |= dstMask; - } - if (srcMask == 1) { - srcMask = 128; - s++; - } - else { - srcMask = srcMask >> 1; - } - if (dstMask == 1) { - dstMask = 128; - d++; - *d = 0; - } - else { - dstMask = dstMask >> 1; - } - } - } - } - src += width_in_bytes; - } -} - - -/** - * Get indexes of color components for a basic color format, such as - * GL_RGBA, GL_RED, GL_LUMINANCE_ALPHA, etc. Return -1 for indexes - * that do not apply. - */ -static void -get_component_indexes(GLenum format, - GLint *redIndex, - GLint *greenIndex, - GLint *blueIndex, - GLint *alphaIndex, - GLint *luminanceIndex, - GLint *intensityIndex) -{ - *redIndex = -1; - *greenIndex = -1; - *blueIndex = -1; - *alphaIndex = -1; - *luminanceIndex = -1; - *intensityIndex = -1; - - switch (format) { - case GL_LUMINANCE: - case GL_LUMINANCE_INTEGER_EXT: - *luminanceIndex = 0; - break; - case GL_LUMINANCE_ALPHA: - case GL_LUMINANCE_ALPHA_INTEGER_EXT: - *luminanceIndex = 0; - *alphaIndex = 1; - break; - case GL_INTENSITY: - *intensityIndex = 0; - break; - case GL_RED: - case GL_RED_INTEGER_EXT: - *redIndex = 0; - break; - case GL_GREEN: - case GL_GREEN_INTEGER_EXT: - *greenIndex = 0; - break; - case GL_BLUE: - case GL_BLUE_INTEGER_EXT: - *blueIndex = 0; - break; - case GL_ALPHA: - case GL_ALPHA_INTEGER_EXT: - *alphaIndex = 0; - break; - case GL_RG: - case GL_RG_INTEGER: - *redIndex = 0; - *greenIndex = 1; - break; - case GL_RGB: - case GL_RGB_INTEGER_EXT: - *redIndex = 0; - *greenIndex = 1; - *blueIndex = 2; - break; - case GL_BGR: - case GL_BGR_INTEGER_EXT: - *blueIndex = 0; - *greenIndex = 1; - *redIndex = 2; - break; - case GL_RGBA: - case GL_RGBA_INTEGER_EXT: - *redIndex = 0; - *greenIndex = 1; - *blueIndex = 2; - *alphaIndex = 3; - break; - case GL_BGRA: - case GL_BGRA_INTEGER: - *redIndex = 2; - *greenIndex = 1; - *blueIndex = 0; - *alphaIndex = 3; - break; - case GL_ABGR_EXT: - *redIndex = 3; - *greenIndex = 2; - *blueIndex = 1; - *alphaIndex = 0; - break; - case GL_DU8DV8_ATI: - case GL_DUDV_ATI: - *redIndex = 0; - *greenIndex = 1; - break; - default: - assert(0 && "bad format in get_component_indexes()"); - } -} - - - -/** - * For small integer types, return the min and max possible values. - * Used for clamping floats to unscaled integer types. - * \return GL_TRUE if type is handled, GL_FALSE otherwise. - */ -static GLboolean -get_type_min_max(GLenum type, GLfloat *min, GLfloat *max) -{ - switch (type) { - case GL_BYTE: - *min = -128.0; - *max = 127.0; - return GL_TRUE; - case GL_UNSIGNED_BYTE: - *min = 0.0; - *max = 255.0; - return GL_TRUE; - case GL_SHORT: - *min = -32768.0; - *max = 32767.0; - return GL_TRUE; - case GL_UNSIGNED_SHORT: - *min = 0.0; - *max = 65535.0; - return GL_TRUE; - default: - return GL_FALSE; - } -} - - - -/** - * Used to pack an array [][4] of RGBA float colors as specified - * by the dstFormat, dstType and dstPacking. Used by glReadPixels. - * Historically, the RGBA values were in [0,1] and rescaled to fit - * into GLubytes, etc. But with new integer formats, the RGBA values - * may have any value and we don't always rescale when converting to - * integers. - * - * Note: the rgba values will be modified by this function when any pixel - * transfer ops are enabled. - */ -void -_mesa_pack_rgba_span_float(struct gl_context *ctx, GLuint n, GLfloat rgba[][4], - GLenum dstFormat, GLenum dstType, - GLvoid *dstAddr, - const struct gl_pixelstore_attrib *dstPacking, - GLbitfield transferOps) -{ - GLfloat *luminance; - const GLint comps = _mesa_components_in_format(dstFormat); - const GLboolean intDstFormat = _mesa_is_integer_format(dstFormat); - GLuint i; - - if (dstFormat == GL_LUMINANCE || - dstFormat == GL_LUMINANCE_ALPHA || - dstFormat == GL_LUMINANCE_INTEGER_EXT || - dstFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT) { - luminance = (GLfloat *) malloc(n * sizeof(GLfloat)); - if (!luminance) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel packing"); - return; - } - } - else { - luminance = NULL; - } - - if (transferOps) { - _mesa_apply_rgba_transfer_ops(ctx, transferOps, n, rgba); - } - - /* - * Component clamping (besides clamping to [0,1] in - * _mesa_apply_rgba_transfer_ops()). - */ - if (intDstFormat) { - /* clamping to dest type's min/max values */ - GLfloat min, max; - if (get_type_min_max(dstType, &min, &max)) { - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = CLAMP(rgba[i][RCOMP], min, max); - rgba[i][GCOMP] = CLAMP(rgba[i][GCOMP], min, max); - rgba[i][BCOMP] = CLAMP(rgba[i][BCOMP], min, max); - rgba[i][ACOMP] = CLAMP(rgba[i][ACOMP], min, max); - } - } - } - else if (dstFormat == GL_LUMINANCE || dstFormat == GL_LUMINANCE_ALPHA) { - /* compute luminance values */ - if (transferOps & IMAGE_CLAMP_BIT) { - for (i = 0; i < n; i++) { - GLfloat sum = rgba[i][RCOMP] + rgba[i][GCOMP] + rgba[i][BCOMP]; - luminance[i] = CLAMP(sum, 0.0F, 1.0F); - } - } - else { - for (i = 0; i < n; i++) { - luminance[i] = rgba[i][RCOMP] + rgba[i][GCOMP] + rgba[i][BCOMP]; - } - } - } - - /* - * Pack/store the pixels. Ugh! Lots of cases!!! - */ - switch (dstType) { - case GL_UNSIGNED_BYTE: - { - GLubyte *dst = (GLubyte *) dstAddr; - switch (dstFormat) { - case GL_RED: - for (i=0;iSwapBytes) { - GLint swapSize = _mesa_sizeof_packed_type(dstType); - if (swapSize == 2) { - if (dstPacking->SwapBytes) { - _mesa_swap2((GLushort *) dstAddr, n * comps); - } - } - else if (swapSize == 4) { - if (dstPacking->SwapBytes) { - _mesa_swap4((GLuint *) dstAddr, n * comps); - } - } - } - - free(luminance); -} - - - -#define SWAP2BYTE(VALUE) \ - { \ - GLubyte *bytes = (GLubyte *) &(VALUE); \ - GLubyte tmp = bytes[0]; \ - bytes[0] = bytes[1]; \ - bytes[1] = tmp; \ - } - -#define SWAP4BYTE(VALUE) \ - { \ - GLubyte *bytes = (GLubyte *) &(VALUE); \ - GLubyte tmp = bytes[0]; \ - bytes[0] = bytes[3]; \ - bytes[3] = tmp; \ - tmp = bytes[1]; \ - bytes[1] = bytes[2]; \ - bytes[2] = tmp; \ - } - - -static void -extract_uint_indexes(GLuint n, GLuint indexes[], - GLenum srcFormat, GLenum srcType, const GLvoid *src, - const struct gl_pixelstore_attrib *unpack ) -{ - ASSERT(srcFormat == GL_COLOR_INDEX || srcFormat == GL_STENCIL_INDEX); - - ASSERT(srcType == GL_BITMAP || - srcType == GL_UNSIGNED_BYTE || - srcType == GL_BYTE || - srcType == GL_UNSIGNED_SHORT || - srcType == GL_SHORT || - srcType == GL_UNSIGNED_INT || - srcType == GL_INT || - srcType == GL_UNSIGNED_INT_24_8_EXT || - srcType == GL_HALF_FLOAT_ARB || - srcType == GL_FLOAT); - - switch (srcType) { - case GL_BITMAP: - { - GLubyte *ubsrc = (GLubyte *) src; - if (unpack->LsbFirst) { - GLubyte mask = 1 << (unpack->SkipPixels & 0x7); - GLuint i; - for (i = 0; i < n; i++) { - indexes[i] = (*ubsrc & mask) ? 1 : 0; - if (mask == 128) { - mask = 1; - ubsrc++; - } - else { - mask = mask << 1; - } - } - } - else { - GLubyte mask = 128 >> (unpack->SkipPixels & 0x7); - GLuint i; - for (i = 0; i < n; i++) { - indexes[i] = (*ubsrc & mask) ? 1 : 0; - if (mask == 1) { - mask = 128; - ubsrc++; - } - else { - mask = mask >> 1; - } - } - } - } - break; - case GL_UNSIGNED_BYTE: - { - GLuint i; - const GLubyte *s = (const GLubyte *) src; - for (i = 0; i < n; i++) - indexes[i] = s[i]; - } - break; - case GL_BYTE: - { - GLuint i; - const GLbyte *s = (const GLbyte *) src; - for (i = 0; i < n; i++) - indexes[i] = s[i]; - } - break; - case GL_UNSIGNED_SHORT: - { - GLuint i; - const GLushort *s = (const GLushort *) src; - if (unpack->SwapBytes) { - for (i = 0; i < n; i++) { - GLushort value = s[i]; - SWAP2BYTE(value); - indexes[i] = value; - } - } - else { - for (i = 0; i < n; i++) - indexes[i] = s[i]; - } - } - break; - case GL_SHORT: - { - GLuint i; - const GLshort *s = (const GLshort *) src; - if (unpack->SwapBytes) { - for (i = 0; i < n; i++) { - GLshort value = s[i]; - SWAP2BYTE(value); - indexes[i] = value; - } - } - else { - for (i = 0; i < n; i++) - indexes[i] = s[i]; - } - } - break; - case GL_UNSIGNED_INT: - { - GLuint i; - const GLuint *s = (const GLuint *) src; - if (unpack->SwapBytes) { - for (i = 0; i < n; i++) { - GLuint value = s[i]; - SWAP4BYTE(value); - indexes[i] = value; - } - } - else { - for (i = 0; i < n; i++) - indexes[i] = s[i]; - } - } - break; - case GL_INT: - { - GLuint i; - const GLint *s = (const GLint *) src; - if (unpack->SwapBytes) { - for (i = 0; i < n; i++) { - GLint value = s[i]; - SWAP4BYTE(value); - indexes[i] = value; - } - } - else { - for (i = 0; i < n; i++) - indexes[i] = s[i]; - } - } - break; - case GL_FLOAT: - { - GLuint i; - const GLfloat *s = (const GLfloat *) src; - if (unpack->SwapBytes) { - for (i = 0; i < n; i++) { - GLfloat value = s[i]; - SWAP4BYTE(value); - indexes[i] = (GLuint) value; - } - } - else { - for (i = 0; i < n; i++) - indexes[i] = (GLuint) s[i]; - } - } - break; - case GL_HALF_FLOAT_ARB: - { - GLuint i; - const GLhalfARB *s = (const GLhalfARB *) src; - if (unpack->SwapBytes) { - for (i = 0; i < n; i++) { - GLhalfARB value = s[i]; - SWAP2BYTE(value); - indexes[i] = (GLuint) _mesa_half_to_float(value); - } - } - else { - for (i = 0; i < n; i++) - indexes[i] = (GLuint) _mesa_half_to_float(s[i]); - } - } - break; - case GL_UNSIGNED_INT_24_8_EXT: - { - GLuint i; - const GLuint *s = (const GLuint *) src; - if (unpack->SwapBytes) { - for (i = 0; i < n; i++) { - GLuint value = s[i]; - SWAP4BYTE(value); - indexes[i] = value & 0xff; /* lower 8 bits */ - } - } - else { - for (i = 0; i < n; i++) - indexes[i] = s[i] & 0xff; /* lower 8 bits */ - } - } - break; - - default: - _mesa_problem(NULL, "bad srcType in extract_uint_indexes"); - return; - } -} - - -/** - * Return source/dest RGBA indexes for unpacking pixels. - */ -static void -get_component_mapping(GLenum format, - GLint *rSrc, - GLint *gSrc, - GLint *bSrc, - GLint *aSrc, - GLint *rDst, - GLint *gDst, - GLint *bDst, - GLint *aDst) -{ - switch (format) { - case GL_RED: - case GL_RED_INTEGER_EXT: - *rSrc = 0; - *gSrc = *bSrc = *aSrc = -1; - break; - case GL_GREEN: - case GL_GREEN_INTEGER_EXT: - *gSrc = 0; - *rSrc = *bSrc = *aSrc = -1; - break; - case GL_BLUE: - case GL_BLUE_INTEGER_EXT: - *bSrc = 0; - *rSrc = *gSrc = *aSrc = -1; - break; - case GL_ALPHA: - case GL_ALPHA_INTEGER_EXT: - *rSrc = *gSrc = *bSrc = -1; - *aSrc = 0; - break; - case GL_LUMINANCE: - case GL_LUMINANCE_INTEGER_EXT: - *rSrc = *gSrc = *bSrc = 0; - *aSrc = -1; - break; - case GL_LUMINANCE_ALPHA: - case GL_LUMINANCE_ALPHA_INTEGER_EXT: - *rSrc = *gSrc = *bSrc = 0; - *aSrc = 1; - break; - case GL_INTENSITY: - *rSrc = *gSrc = *bSrc = *aSrc = 0; - break; - case GL_RG: - case GL_RG_INTEGER: - *rSrc = 0; - *gSrc = 1; - *bSrc = -1; - *aSrc = -1; - *rDst = 0; - *gDst = 1; - *bDst = 2; - *aDst = 3; - break; - case GL_RGB: - case GL_RGB_INTEGER: - *rSrc = 0; - *gSrc = 1; - *bSrc = 2; - *aSrc = -1; - *rDst = 0; - *gDst = 1; - *bDst = 2; - *aDst = 3; - break; - case GL_BGR: - *rSrc = 2; - *gSrc = 1; - *bSrc = 0; - *aSrc = -1; - *rDst = 2; - *gDst = 1; - *bDst = 0; - *aDst = 3; - break; - case GL_RGBA: - case GL_RGBA_INTEGER: - *rSrc = 0; - *gSrc = 1; - *bSrc = 2; - *aSrc = 3; - *rDst = 0; - *gDst = 1; - *bDst = 2; - *aDst = 3; - break; - case GL_BGRA: - *rSrc = 2; - *gSrc = 1; - *bSrc = 0; - *aSrc = 3; - *rDst = 2; - *gDst = 1; - *bDst = 0; - *aDst = 3; - break; - case GL_ABGR_EXT: - *rSrc = 3; - *gSrc = 2; - *bSrc = 1; - *aSrc = 0; - *rDst = 3; - *gDst = 2; - *bDst = 1; - *aDst = 0; - break; - case GL_DU8DV8_ATI: - case GL_DUDV_ATI: - *rSrc = 0; - *gSrc = 1; - *bSrc = -1; - *aSrc = -1; - break; - default: - _mesa_problem(NULL, "bad srcFormat %s in get_component_mapping", - _mesa_lookup_enum_by_nr(format)); - return; - } -} - - - -/* - * This function extracts floating point RGBA values from arbitrary - * image data. srcFormat and srcType are the format and type parameters - * passed to glDrawPixels, glTexImage[123]D, glTexSubImage[123]D, etc. - * - * Refering to section 3.6.4 of the OpenGL 1.2 spec, this function - * implements the "Conversion to floating point", "Conversion to RGB", - * and "Final Expansion to RGBA" operations. - * - * Args: n - number of pixels - * rgba - output colors - * srcFormat - format of incoming data - * srcType - data type of incoming data - * src - source data pointer - * swapBytes - perform byteswapping of incoming data? - */ -static void -extract_float_rgba(GLuint n, GLfloat rgba[][4], - GLenum srcFormat, GLenum srcType, const GLvoid *src, - GLboolean swapBytes) -{ - GLint rSrc, gSrc, bSrc, aSrc; - GLint stride; - GLint rDst, bDst, gDst, aDst; - GLboolean intFormat; - GLfloat rs = 1.0f, gs = 1.0f, bs = 1.0f, as = 1.0f; /* scale factors */ - - ASSERT(srcFormat == GL_RED || - srcFormat == GL_GREEN || - srcFormat == GL_BLUE || - srcFormat == GL_ALPHA || - srcFormat == GL_LUMINANCE || - srcFormat == GL_LUMINANCE_ALPHA || - srcFormat == GL_INTENSITY || - srcFormat == GL_RG || - srcFormat == GL_RGB || - srcFormat == GL_BGR || - srcFormat == GL_RGBA || - srcFormat == GL_BGRA || - srcFormat == GL_ABGR_EXT || - srcFormat == GL_DU8DV8_ATI || - srcFormat == GL_DUDV_ATI || - srcFormat == GL_RED_INTEGER_EXT || - srcFormat == GL_GREEN_INTEGER_EXT || - srcFormat == GL_BLUE_INTEGER_EXT || - srcFormat == GL_ALPHA_INTEGER_EXT || - srcFormat == GL_RGB_INTEGER_EXT || - srcFormat == GL_RGBA_INTEGER_EXT || - srcFormat == GL_BGR_INTEGER_EXT || - srcFormat == GL_BGRA_INTEGER_EXT || - srcFormat == GL_LUMINANCE_INTEGER_EXT || - srcFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT); - - ASSERT(srcType == GL_UNSIGNED_BYTE || - srcType == GL_BYTE || - srcType == GL_UNSIGNED_SHORT || - srcType == GL_SHORT || - srcType == GL_UNSIGNED_INT || - srcType == GL_INT || - srcType == GL_HALF_FLOAT_ARB || - srcType == GL_FLOAT || - srcType == GL_UNSIGNED_BYTE_3_3_2 || - srcType == GL_UNSIGNED_BYTE_2_3_3_REV || - srcType == GL_UNSIGNED_SHORT_5_6_5 || - srcType == GL_UNSIGNED_SHORT_5_6_5_REV || - srcType == GL_UNSIGNED_SHORT_4_4_4_4 || - srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV || - srcType == GL_UNSIGNED_SHORT_5_5_5_1 || - srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV || - srcType == GL_UNSIGNED_INT_8_8_8_8 || - srcType == GL_UNSIGNED_INT_8_8_8_8_REV || - srcType == GL_UNSIGNED_INT_10_10_10_2 || - srcType == GL_UNSIGNED_INT_2_10_10_10_REV || - srcType == GL_UNSIGNED_INT_5_9_9_9_REV || - srcType == GL_UNSIGNED_INT_10F_11F_11F_REV); - - get_component_mapping(srcFormat, - &rSrc, &gSrc, &bSrc, &aSrc, - &rDst, &gDst, &bDst, &aDst); - - stride = _mesa_components_in_format(srcFormat); - - intFormat = _mesa_is_integer_format(srcFormat); - -#define PROCESS(SRC_INDEX, DST_INDEX, DEFAULT_FLT, DEFAULT_INT, TYPE, CONVERSION) \ - if ((SRC_INDEX) < 0) { \ - GLuint i; \ - if (intFormat) { \ - for (i = 0; i < n; i++) { \ - rgba[i][DST_INDEX] = DEFAULT_INT; \ - } \ - } \ - else { \ - for (i = 0; i < n; i++) { \ - rgba[i][DST_INDEX] = DEFAULT_FLT; \ - } \ - } \ - } \ - else if (swapBytes) { \ - const TYPE *s = (const TYPE *) src; \ - GLuint i; \ - for (i = 0; i < n; i++) { \ - TYPE value = s[SRC_INDEX]; \ - if (sizeof(TYPE) == 2) { \ - SWAP2BYTE(value); \ - } \ - else if (sizeof(TYPE) == 4) { \ - SWAP4BYTE(value); \ - } \ - if (intFormat) \ - rgba[i][DST_INDEX] = (GLfloat) value; \ - else \ - rgba[i][DST_INDEX] = (GLfloat) CONVERSION(value); \ - s += stride; \ - } \ - } \ - else { \ - const TYPE *s = (const TYPE *) src; \ - GLuint i; \ - if (intFormat) { \ - for (i = 0; i < n; i++) { \ - rgba[i][DST_INDEX] = (GLfloat) s[SRC_INDEX]; \ - s += stride; \ - } \ - } \ - else { \ - for (i = 0; i < n; i++) { \ - rgba[i][DST_INDEX] = (GLfloat) CONVERSION(s[SRC_INDEX]); \ - s += stride; \ - } \ - } \ - } - - switch (srcType) { - case GL_UNSIGNED_BYTE: - PROCESS(rSrc, RCOMP, 0.0F, 0, GLubyte, UBYTE_TO_FLOAT); - PROCESS(gSrc, GCOMP, 0.0F, 0, GLubyte, UBYTE_TO_FLOAT); - PROCESS(bSrc, BCOMP, 0.0F, 0, GLubyte, UBYTE_TO_FLOAT); - PROCESS(aSrc, ACOMP, 1.0F, 255, GLubyte, UBYTE_TO_FLOAT); - break; - case GL_BYTE: - PROCESS(rSrc, RCOMP, 0.0F, 0, GLbyte, BYTE_TO_FLOAT); - PROCESS(gSrc, GCOMP, 0.0F, 0, GLbyte, BYTE_TO_FLOAT); - PROCESS(bSrc, BCOMP, 0.0F, 0, GLbyte, BYTE_TO_FLOAT); - PROCESS(aSrc, ACOMP, 1.0F, 127, GLbyte, BYTE_TO_FLOAT); - break; - case GL_UNSIGNED_SHORT: - PROCESS(rSrc, RCOMP, 0.0F, 0, GLushort, USHORT_TO_FLOAT); - PROCESS(gSrc, GCOMP, 0.0F, 0, GLushort, USHORT_TO_FLOAT); - PROCESS(bSrc, BCOMP, 0.0F, 0, GLushort, USHORT_TO_FLOAT); - PROCESS(aSrc, ACOMP, 1.0F, 0xffff, GLushort, USHORT_TO_FLOAT); - break; - case GL_SHORT: - PROCESS(rSrc, RCOMP, 0.0F, 0, GLshort, SHORT_TO_FLOAT); - PROCESS(gSrc, GCOMP, 0.0F, 0, GLshort, SHORT_TO_FLOAT); - PROCESS(bSrc, BCOMP, 0.0F, 0, GLshort, SHORT_TO_FLOAT); - PROCESS(aSrc, ACOMP, 1.0F, 32767, GLshort, SHORT_TO_FLOAT); - break; - case GL_UNSIGNED_INT: - PROCESS(rSrc, RCOMP, 0.0F, 0, GLuint, UINT_TO_FLOAT); - PROCESS(gSrc, GCOMP, 0.0F, 0, GLuint, UINT_TO_FLOAT); - PROCESS(bSrc, BCOMP, 0.0F, 0, GLuint, UINT_TO_FLOAT); - PROCESS(aSrc, ACOMP, 1.0F, 0xffffffff, GLuint, UINT_TO_FLOAT); - break; - case GL_INT: - PROCESS(rSrc, RCOMP, 0.0F, 0, GLint, INT_TO_FLOAT); - PROCESS(gSrc, GCOMP, 0.0F, 0, GLint, INT_TO_FLOAT); - PROCESS(bSrc, BCOMP, 0.0F, 0, GLint, INT_TO_FLOAT); - PROCESS(aSrc, ACOMP, 1.0F, 2147483647, GLint, INT_TO_FLOAT); - break; - case GL_FLOAT: - PROCESS(rSrc, RCOMP, 0.0F, 0.0F, GLfloat, (GLfloat)); - PROCESS(gSrc, GCOMP, 0.0F, 0.0F, GLfloat, (GLfloat)); - PROCESS(bSrc, BCOMP, 0.0F, 0.0F, GLfloat, (GLfloat)); - PROCESS(aSrc, ACOMP, 1.0F, 1.0F, GLfloat, (GLfloat)); - break; - case GL_HALF_FLOAT_ARB: - PROCESS(rSrc, RCOMP, 0.0F, 0.0F, GLhalfARB, _mesa_half_to_float); - PROCESS(gSrc, GCOMP, 0.0F, 0.0F, GLhalfARB, _mesa_half_to_float); - PROCESS(bSrc, BCOMP, 0.0F, 0.0F, GLhalfARB, _mesa_half_to_float); - PROCESS(aSrc, ACOMP, 1.0F, 1.0F, GLhalfARB, _mesa_half_to_float); - break; - case GL_UNSIGNED_BYTE_3_3_2: - { - const GLubyte *ubsrc = (const GLubyte *) src; - GLuint i; - if (!intFormat) { - rs = 1.0F / 7.0F; - gs = 1.0F / 7.0F; - bs = 1.0F / 3.0F; - } - for (i = 0; i < n; i ++) { - GLubyte p = ubsrc[i]; - rgba[i][rDst] = ((p >> 5) ) * rs; - rgba[i][gDst] = ((p >> 2) & 0x7) * gs; - rgba[i][bDst] = ((p ) & 0x3) * bs; - rgba[i][aDst] = 1.0F; - } - } - break; - case GL_UNSIGNED_BYTE_2_3_3_REV: - { - const GLubyte *ubsrc = (const GLubyte *) src; - GLuint i; - if (!intFormat) { - rs = 1.0F / 7.0F; - gs = 1.0F / 7.0F; - bs = 1.0F / 3.0F; - } - for (i = 0; i < n; i ++) { - GLubyte p = ubsrc[i]; - rgba[i][rDst] = ((p ) & 0x7) * rs; - rgba[i][gDst] = ((p >> 3) & 0x7) * gs; - rgba[i][bDst] = ((p >> 6) ) * bs; - rgba[i][aDst] = 1.0F; - } - } - break; - case GL_UNSIGNED_SHORT_5_6_5: - if (!intFormat) { - rs = 1.0F / 31.0F; - gs = 1.0F / 63.0F; - bs = 1.0F / 31.0F; - } - if (swapBytes) { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - SWAP2BYTE(p); - rgba[i][rDst] = ((p >> 11) ) * rs; - rgba[i][gDst] = ((p >> 5) & 0x3f) * gs; - rgba[i][bDst] = ((p ) & 0x1f) * bs; - rgba[i][aDst] = 1.0F; - } - } - else { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - rgba[i][rDst] = ((p >> 11) ) * rs; - rgba[i][gDst] = ((p >> 5) & 0x3f) * gs; - rgba[i][bDst] = ((p ) & 0x1f) * bs; - rgba[i][aDst] = 1.0F; - } - } - break; - case GL_UNSIGNED_SHORT_5_6_5_REV: - if (!intFormat) { - rs = 1.0F / 31.0F; - gs = 1.0F / 63.0F; - bs = 1.0F / 31.0F; - } - if (swapBytes) { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - SWAP2BYTE(p); - rgba[i][rDst] = ((p ) & 0x1f) * rs; - rgba[i][gDst] = ((p >> 5) & 0x3f) * gs; - rgba[i][bDst] = ((p >> 11) ) * bs; - rgba[i][aDst] = 1.0F; - } - } - else { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - rgba[i][rDst] = ((p ) & 0x1f) * rs; - rgba[i][gDst] = ((p >> 5) & 0x3f) * gs; - rgba[i][bDst] = ((p >> 11) ) * bs; - rgba[i][aDst] = 1.0F; - } - } - break; - case GL_UNSIGNED_SHORT_4_4_4_4: - if (!intFormat) { - rs = gs = bs = as = 1.0F / 15.0F; - } - if (swapBytes) { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - SWAP2BYTE(p); - rgba[i][rDst] = ((p >> 12) ) * rs; - rgba[i][gDst] = ((p >> 8) & 0xf) * gs; - rgba[i][bDst] = ((p >> 4) & 0xf) * bs; - rgba[i][aDst] = ((p ) & 0xf) * as; - } - } - else { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - rgba[i][rDst] = ((p >> 12) ) * rs; - rgba[i][gDst] = ((p >> 8) & 0xf) * gs; - rgba[i][bDst] = ((p >> 4) & 0xf) * bs; - rgba[i][aDst] = ((p ) & 0xf) * as; - } - } - break; - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - if (!intFormat) { - rs = gs = bs = as = 1.0F / 15.0F; - } - if (swapBytes) { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - SWAP2BYTE(p); - rgba[i][rDst] = ((p ) & 0xf) * rs; - rgba[i][gDst] = ((p >> 4) & 0xf) * gs; - rgba[i][bDst] = ((p >> 8) & 0xf) * bs; - rgba[i][aDst] = ((p >> 12) ) * as; - } - } - else { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - rgba[i][rDst] = ((p ) & 0xf) * rs; - rgba[i][gDst] = ((p >> 4) & 0xf) * gs; - rgba[i][bDst] = ((p >> 8) & 0xf) * bs; - rgba[i][aDst] = ((p >> 12) ) * as; - } - } - break; - case GL_UNSIGNED_SHORT_5_5_5_1: - if (!intFormat) { - rs = gs = bs = 1.0F / 31.0F; - } - if (swapBytes) { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - SWAP2BYTE(p); - rgba[i][rDst] = ((p >> 11) ) * rs; - rgba[i][gDst] = ((p >> 6) & 0x1f) * gs; - rgba[i][bDst] = ((p >> 1) & 0x1f) * bs; - rgba[i][aDst] = ((p ) & 0x1) * as; - } - } - else { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - rgba[i][rDst] = ((p >> 11) ) * rs; - rgba[i][gDst] = ((p >> 6) & 0x1f) * gs; - rgba[i][bDst] = ((p >> 1) & 0x1f) * bs; - rgba[i][aDst] = ((p ) & 0x1) * as; - } - } - break; - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - if (!intFormat) { - rs = gs = bs = 1.0F / 31.0F; - } - if (swapBytes) { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - SWAP2BYTE(p); - rgba[i][rDst] = ((p ) & 0x1f) * rs; - rgba[i][gDst] = ((p >> 5) & 0x1f) * gs; - rgba[i][bDst] = ((p >> 10) & 0x1f) * bs; - rgba[i][aDst] = ((p >> 15) ) * as; - } - } - else { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - rgba[i][rDst] = ((p ) & 0x1f) * rs; - rgba[i][gDst] = ((p >> 5) & 0x1f) * gs; - rgba[i][bDst] = ((p >> 10) & 0x1f) * bs; - rgba[i][aDst] = ((p >> 15) ) * as; - } - } - break; - case GL_UNSIGNED_INT_8_8_8_8: - if (swapBytes) { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - if (intFormat) { - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - rgba[i][rDst] = (GLfloat) ((p ) & 0xff); - rgba[i][gDst] = (GLfloat) ((p >> 8) & 0xff); - rgba[i][bDst] = (GLfloat) ((p >> 16) & 0xff); - rgba[i][aDst] = (GLfloat) ((p >> 24) ); - } - } - else { - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - rgba[i][rDst] = UBYTE_TO_FLOAT((p ) & 0xff); - rgba[i][gDst] = UBYTE_TO_FLOAT((p >> 8) & 0xff); - rgba[i][bDst] = UBYTE_TO_FLOAT((p >> 16) & 0xff); - rgba[i][aDst] = UBYTE_TO_FLOAT((p >> 24) ); - } - } - } - else { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - if (intFormat) { - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - rgba[i][rDst] = (GLfloat) ((p >> 24) ); - rgba[i][gDst] = (GLfloat) ((p >> 16) & 0xff); - rgba[i][bDst] = (GLfloat) ((p >> 8) & 0xff); - rgba[i][aDst] = (GLfloat) ((p ) & 0xff); - } - } - else { - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - rgba[i][rDst] = UBYTE_TO_FLOAT((p >> 24) ); - rgba[i][gDst] = UBYTE_TO_FLOAT((p >> 16) & 0xff); - rgba[i][bDst] = UBYTE_TO_FLOAT((p >> 8) & 0xff); - rgba[i][aDst] = UBYTE_TO_FLOAT((p ) & 0xff); - } - } - } - break; - case GL_UNSIGNED_INT_8_8_8_8_REV: - if (swapBytes) { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - if (intFormat) { - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - rgba[i][rDst] = (GLfloat) ((p >> 24) ); - rgba[i][gDst] = (GLfloat) ((p >> 16) & 0xff); - rgba[i][bDst] = (GLfloat) ((p >> 8) & 0xff); - rgba[i][aDst] = (GLfloat) ((p ) & 0xff); - } - } - else { - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - rgba[i][rDst] = UBYTE_TO_FLOAT((p >> 24) ); - rgba[i][gDst] = UBYTE_TO_FLOAT((p >> 16) & 0xff); - rgba[i][bDst] = UBYTE_TO_FLOAT((p >> 8) & 0xff); - rgba[i][aDst] = UBYTE_TO_FLOAT((p ) & 0xff); - } - } - } - else { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - if (intFormat) { - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - rgba[i][rDst] = (GLfloat) ((p ) & 0xff); - rgba[i][gDst] = (GLfloat) ((p >> 8) & 0xff); - rgba[i][bDst] = (GLfloat) ((p >> 16) & 0xff); - rgba[i][aDst] = (GLfloat) ((p >> 24) ); - } - } - else { - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - rgba[i][rDst] = UBYTE_TO_FLOAT((p ) & 0xff); - rgba[i][gDst] = UBYTE_TO_FLOAT((p >> 8) & 0xff); - rgba[i][bDst] = UBYTE_TO_FLOAT((p >> 16) & 0xff); - rgba[i][aDst] = UBYTE_TO_FLOAT((p >> 24) ); - } - } - } - break; - case GL_UNSIGNED_INT_10_10_10_2: - if (!intFormat) { - rs = 1.0F / 1023.0F; - gs = 1.0F / 1023.0F; - bs = 1.0F / 1023.0F; - as = 1.0F / 3.0F; - } - if (swapBytes) { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - SWAP4BYTE(p); - rgba[i][rDst] = ((p >> 22) ) * rs; - rgba[i][gDst] = ((p >> 12) & 0x3ff) * gs; - rgba[i][bDst] = ((p >> 2) & 0x3ff) * bs; - rgba[i][aDst] = ((p ) & 0x3 ) * as; - } - } - else { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - rgba[i][rDst] = ((p >> 22) ) * rs; - rgba[i][gDst] = ((p >> 12) & 0x3ff) * gs; - rgba[i][bDst] = ((p >> 2) & 0x3ff) * bs; - rgba[i][aDst] = ((p ) & 0x3 ) * as; - } - } - break; - case GL_UNSIGNED_INT_2_10_10_10_REV: - if (!intFormat) { - rs = 1.0F / 1023.0F; - gs = 1.0F / 1023.0F; - bs = 1.0F / 1023.0F; - as = 1.0F / 3.0F; - } - if (swapBytes) { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - SWAP4BYTE(p); - rgba[i][rDst] = ((p ) & 0x3ff) * rs; - rgba[i][gDst] = ((p >> 10) & 0x3ff) * gs; - rgba[i][bDst] = ((p >> 20) & 0x3ff) * bs; - rgba[i][aDst] = ((p >> 30) ) * as; - } - } - else { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - rgba[i][rDst] = ((p ) & 0x3ff) * rs; - rgba[i][gDst] = ((p >> 10) & 0x3ff) * gs; - rgba[i][bDst] = ((p >> 20) & 0x3ff) * bs; - rgba[i][aDst] = ((p >> 30) ) * as; - } - } - break; - case GL_UNSIGNED_INT_5_9_9_9_REV: - if (swapBytes) { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - GLfloat f[3]; - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - SWAP4BYTE(p); - rgb9e5_to_float3(p, f); - rgba[i][rDst] = f[0]; - rgba[i][gDst] = f[1]; - rgba[i][bDst] = f[2]; - rgba[i][aDst] = 1.0F; - } - } - else { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - GLfloat f[3]; - for (i = 0; i < n; i ++) { - rgb9e5_to_float3(uisrc[i], f); - rgba[i][rDst] = f[0]; - rgba[i][gDst] = f[1]; - rgba[i][bDst] = f[2]; - rgba[i][aDst] = 1.0F; - } - } - break; - case GL_UNSIGNED_INT_10F_11F_11F_REV: - if (swapBytes) { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - GLfloat f[3]; - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - SWAP4BYTE(p); - r11g11b10f_to_float3(p, f); - rgba[i][rDst] = f[0]; - rgba[i][gDst] = f[1]; - rgba[i][bDst] = f[2]; - rgba[i][aDst] = 1.0F; - } - } - else { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - GLfloat f[3]; - for (i = 0; i < n; i ++) { - r11g11b10f_to_float3(uisrc[i], f); - rgba[i][rDst] = f[0]; - rgba[i][gDst] = f[1]; - rgba[i][bDst] = f[2]; - rgba[i][aDst] = 1.0F; - } - } - break; - default: - _mesa_problem(NULL, "bad srcType in extract float data"); - break; - } -#undef PROCESS -} - - -static INLINE GLuint -clamp_byte_to_uint(GLbyte b) -{ - return b < 0 ? 0 : b; -} - - -static INLINE GLuint -clamp_short_to_uint(GLshort s) -{ - return s < 0 ? 0 : s; -} - - -static INLINE GLuint -clamp_int_to_uint(GLint i) -{ - return i < 0 ? 0 : i; -} - - -static INLINE GLuint -clamp_float_to_uint(GLfloat f) -{ - return f < 0.0F ? 0 : IROUND(f); -} - - -static INLINE GLuint -clamp_half_to_uint(GLhalfARB h) -{ - GLfloat f = _mesa_half_to_float(h); - return f < 0.0F ? 0 : IROUND(f); -} - - -/** - * \sa extract_float_rgba() - */ -static void -extract_uint_rgba(GLuint n, GLuint rgba[][4], - GLenum srcFormat, GLenum srcType, const GLvoid *src, - GLboolean swapBytes) -{ - GLint rSrc, gSrc, bSrc, aSrc; - GLint stride; - GLint rDst, bDst, gDst, aDst; - GLboolean intFormat; - - ASSERT(srcFormat == GL_RED || - srcFormat == GL_GREEN || - srcFormat == GL_BLUE || - srcFormat == GL_ALPHA || - srcFormat == GL_LUMINANCE || - srcFormat == GL_LUMINANCE_ALPHA || - srcFormat == GL_INTENSITY || - srcFormat == GL_RG || - srcFormat == GL_RGB || - srcFormat == GL_BGR || - srcFormat == GL_RGBA || - srcFormat == GL_BGRA || - srcFormat == GL_ABGR_EXT || - srcFormat == GL_DU8DV8_ATI || - srcFormat == GL_DUDV_ATI || - srcFormat == GL_RED_INTEGER_EXT || - srcFormat == GL_GREEN_INTEGER_EXT || - srcFormat == GL_BLUE_INTEGER_EXT || - srcFormat == GL_ALPHA_INTEGER_EXT || - srcFormat == GL_RGB_INTEGER_EXT || - srcFormat == GL_RGBA_INTEGER_EXT || - srcFormat == GL_BGR_INTEGER_EXT || - srcFormat == GL_BGRA_INTEGER_EXT || - srcFormat == GL_LUMINANCE_INTEGER_EXT || - srcFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT); - - ASSERT(srcType == GL_UNSIGNED_BYTE || - srcType == GL_BYTE || - srcType == GL_UNSIGNED_SHORT || - srcType == GL_SHORT || - srcType == GL_UNSIGNED_INT || - srcType == GL_INT || - srcType == GL_HALF_FLOAT_ARB || - srcType == GL_FLOAT || - srcType == GL_UNSIGNED_BYTE_3_3_2 || - srcType == GL_UNSIGNED_BYTE_2_3_3_REV || - srcType == GL_UNSIGNED_SHORT_5_6_5 || - srcType == GL_UNSIGNED_SHORT_5_6_5_REV || - srcType == GL_UNSIGNED_SHORT_4_4_4_4 || - srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV || - srcType == GL_UNSIGNED_SHORT_5_5_5_1 || - srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV || - srcType == GL_UNSIGNED_INT_8_8_8_8 || - srcType == GL_UNSIGNED_INT_8_8_8_8_REV || - srcType == GL_UNSIGNED_INT_10_10_10_2 || - srcType == GL_UNSIGNED_INT_2_10_10_10_REV || - srcType == GL_UNSIGNED_INT_5_9_9_9_REV || - srcType == GL_UNSIGNED_INT_10F_11F_11F_REV); - - get_component_mapping(srcFormat, - &rSrc, &gSrc, &bSrc, &aSrc, - &rDst, &gDst, &bDst, &aDst); - - stride = _mesa_components_in_format(srcFormat); - - intFormat = _mesa_is_integer_format(srcFormat); - -#define PROCESS(SRC_INDEX, DST_INDEX, DEFAULT, TYPE, CONVERSION) \ - if ((SRC_INDEX) < 0) { \ - GLuint i; \ - for (i = 0; i < n; i++) { \ - rgba[i][DST_INDEX] = DEFAULT; \ - } \ - } \ - else if (swapBytes) { \ - const TYPE *s = (const TYPE *) src; \ - GLuint i; \ - for (i = 0; i < n; i++) { \ - TYPE value = s[SRC_INDEX]; \ - if (sizeof(TYPE) == 2) { \ - SWAP2BYTE(value); \ - } \ - else if (sizeof(TYPE) == 4) { \ - SWAP4BYTE(value); \ - } \ - rgba[i][DST_INDEX] = CONVERSION(value); \ - s += stride; \ - } \ - } \ - else { \ - const TYPE *s = (const TYPE *) src; \ - GLuint i; \ - for (i = 0; i < n; i++) { \ - rgba[i][DST_INDEX] = CONVERSION(s[SRC_INDEX]); \ - s += stride; \ - } \ - } - - switch (srcType) { - case GL_UNSIGNED_BYTE: - PROCESS(rSrc, RCOMP, 0, GLubyte, (GLuint)); - PROCESS(gSrc, GCOMP, 0, GLubyte, (GLuint)); - PROCESS(bSrc, BCOMP, 0, GLubyte, (GLuint)); - PROCESS(aSrc, ACOMP, 1, GLubyte, (GLuint)); - break; - case GL_BYTE: - PROCESS(rSrc, RCOMP, 0, GLbyte, clamp_byte_to_uint); - PROCESS(gSrc, GCOMP, 0, GLbyte, clamp_byte_to_uint); - PROCESS(bSrc, BCOMP, 0, GLbyte, clamp_byte_to_uint); - PROCESS(aSrc, ACOMP, 1, GLbyte, clamp_byte_to_uint); - break; - case GL_UNSIGNED_SHORT: - PROCESS(rSrc, RCOMP, 0, GLushort, (GLuint)); - PROCESS(gSrc, GCOMP, 0, GLushort, (GLuint)); - PROCESS(bSrc, BCOMP, 0, GLushort, (GLuint)); - PROCESS(aSrc, ACOMP, 1, GLushort, (GLuint)); - break; - case GL_SHORT: - PROCESS(rSrc, RCOMP, 0, GLshort, clamp_short_to_uint); - PROCESS(gSrc, GCOMP, 0, GLshort, clamp_short_to_uint); - PROCESS(bSrc, BCOMP, 0, GLshort, clamp_short_to_uint); - PROCESS(aSrc, ACOMP, 1, GLshort, clamp_short_to_uint); - break; - case GL_UNSIGNED_INT: - PROCESS(rSrc, RCOMP, 0, GLuint, (GLuint)); - PROCESS(gSrc, GCOMP, 0, GLuint, (GLuint)); - PROCESS(bSrc, BCOMP, 0, GLuint, (GLuint)); - PROCESS(aSrc, ACOMP, 1, GLuint, (GLuint)); - break; - case GL_INT: - PROCESS(rSrc, RCOMP, 0, GLint, clamp_int_to_uint); - PROCESS(gSrc, GCOMP, 0, GLint, clamp_int_to_uint); - PROCESS(bSrc, BCOMP, 0, GLint, clamp_int_to_uint); - PROCESS(aSrc, ACOMP, 1, GLint, clamp_int_to_uint); - break; - case GL_FLOAT: - PROCESS(rSrc, RCOMP, 0, GLfloat, clamp_float_to_uint); - PROCESS(gSrc, GCOMP, 0, GLfloat, clamp_float_to_uint); - PROCESS(bSrc, BCOMP, 0, GLfloat, clamp_float_to_uint); - PROCESS(aSrc, ACOMP, 1, GLfloat, clamp_float_to_uint); - break; - case GL_HALF_FLOAT_ARB: - PROCESS(rSrc, RCOMP, 0, GLhalfARB, clamp_half_to_uint); - PROCESS(gSrc, GCOMP, 0, GLhalfARB, clamp_half_to_uint); - PROCESS(bSrc, BCOMP, 0, GLhalfARB, clamp_half_to_uint); - PROCESS(aSrc, ACOMP, 1, GLhalfARB, clamp_half_to_uint); - break; - case GL_UNSIGNED_BYTE_3_3_2: - { - const GLubyte *ubsrc = (const GLubyte *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLubyte p = ubsrc[i]; - rgba[i][rDst] = ((p >> 5) ); - rgba[i][gDst] = ((p >> 2) & 0x7); - rgba[i][bDst] = ((p ) & 0x3); - rgba[i][aDst] = 1; - } - } - break; - case GL_UNSIGNED_BYTE_2_3_3_REV: - { - const GLubyte *ubsrc = (const GLubyte *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLubyte p = ubsrc[i]; - rgba[i][rDst] = ((p ) & 0x7); - rgba[i][gDst] = ((p >> 3) & 0x7); - rgba[i][bDst] = ((p >> 6) ); - rgba[i][aDst] = 1; - } - } - break; - case GL_UNSIGNED_SHORT_5_6_5: - if (swapBytes) { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - SWAP2BYTE(p); - rgba[i][rDst] = ((p >> 11) ); - rgba[i][gDst] = ((p >> 5) & 0x3f); - rgba[i][bDst] = ((p ) & 0x1f); - rgba[i][aDst] = 1; - } - } - else { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - rgba[i][rDst] = ((p >> 11) ); - rgba[i][gDst] = ((p >> 5) & 0x3f); - rgba[i][bDst] = ((p ) & 0x1f); - rgba[i][aDst] = 1; - } - } - break; - case GL_UNSIGNED_SHORT_5_6_5_REV: - if (swapBytes) { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - SWAP2BYTE(p); - rgba[i][rDst] = ((p ) & 0x1f); - rgba[i][gDst] = ((p >> 5) & 0x3f); - rgba[i][bDst] = ((p >> 11) ); - rgba[i][aDst] = 1; - } - } - else { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - rgba[i][rDst] = ((p ) & 0x1f); - rgba[i][gDst] = ((p >> 5) & 0x3f); - rgba[i][bDst] = ((p >> 11) ); - rgba[i][aDst] = 1; - } - } - break; - case GL_UNSIGNED_SHORT_4_4_4_4: - if (swapBytes) { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - SWAP2BYTE(p); - rgba[i][rDst] = ((p >> 12) ); - rgba[i][gDst] = ((p >> 8) & 0xf); - rgba[i][bDst] = ((p >> 4) & 0xf); - rgba[i][aDst] = ((p ) & 0xf); - } - } - else { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - rgba[i][rDst] = ((p >> 12) ); - rgba[i][gDst] = ((p >> 8) & 0xf); - rgba[i][bDst] = ((p >> 4) & 0xf); - rgba[i][aDst] = ((p ) & 0xf); - } - } - break; - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - if (swapBytes) { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - SWAP2BYTE(p); - rgba[i][rDst] = ((p ) & 0xf); - rgba[i][gDst] = ((p >> 4) & 0xf); - rgba[i][bDst] = ((p >> 8) & 0xf); - rgba[i][aDst] = ((p >> 12) ); - } - } - else { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - rgba[i][rDst] = ((p ) & 0xf); - rgba[i][gDst] = ((p >> 4) & 0xf); - rgba[i][bDst] = ((p >> 8) & 0xf); - rgba[i][aDst] = ((p >> 12) ); - } - } - break; - case GL_UNSIGNED_SHORT_5_5_5_1: - if (swapBytes) { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - SWAP2BYTE(p); - rgba[i][rDst] = ((p >> 11) ); - rgba[i][gDst] = ((p >> 6) & 0x1f); - rgba[i][bDst] = ((p >> 1) & 0x1f); - rgba[i][aDst] = ((p ) & 0x1 ); - } - } - else { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - rgba[i][rDst] = ((p >> 11) ); - rgba[i][gDst] = ((p >> 6) & 0x1f); - rgba[i][bDst] = ((p >> 1) & 0x1f); - rgba[i][aDst] = ((p ) & 0x1 ); - } - } - break; - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - if (swapBytes) { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - SWAP2BYTE(p); - rgba[i][rDst] = ((p ) & 0x1f); - rgba[i][gDst] = ((p >> 5) & 0x1f); - rgba[i][bDst] = ((p >> 10) & 0x1f); - rgba[i][aDst] = ((p >> 15) ); - } - } - else { - const GLushort *ussrc = (const GLushort *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLushort p = ussrc[i]; - rgba[i][rDst] = ((p ) & 0x1f); - rgba[i][gDst] = ((p >> 5) & 0x1f); - rgba[i][bDst] = ((p >> 10) & 0x1f); - rgba[i][aDst] = ((p >> 15) ); - } - } - break; - case GL_UNSIGNED_INT_8_8_8_8: - if (swapBytes) { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - rgba[i][rDst] = ((p ) & 0xff); - rgba[i][gDst] = ((p >> 8) & 0xff); - rgba[i][bDst] = ((p >> 16) & 0xff); - rgba[i][aDst] = ((p >> 24) ); - } - } - else { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - rgba[i][rDst] = ((p >> 24) ); - rgba[i][gDst] = ((p >> 16) & 0xff); - rgba[i][bDst] = ((p >> 8) & 0xff); - rgba[i][aDst] = ((p ) & 0xff); - } - } - break; - case GL_UNSIGNED_INT_8_8_8_8_REV: - if (swapBytes) { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - rgba[i][rDst] = ((p >> 24) ); - rgba[i][gDst] = ((p >> 16) & 0xff); - rgba[i][bDst] = ((p >> 8) & 0xff); - rgba[i][aDst] = ((p ) & 0xff); - } - } - else { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - rgba[i][rDst] = ((p ) & 0xff); - rgba[i][gDst] = ((p >> 8) & 0xff); - rgba[i][bDst] = ((p >> 16) & 0xff); - rgba[i][aDst] = ((p >> 24) ); - } - } - break; - case GL_UNSIGNED_INT_10_10_10_2: - if (swapBytes) { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - SWAP4BYTE(p); - rgba[i][rDst] = ((p >> 22) ); - rgba[i][gDst] = ((p >> 12) & 0x3ff); - rgba[i][bDst] = ((p >> 2) & 0x3ff); - rgba[i][aDst] = ((p ) & 0x3 ); - } - } - else { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - rgba[i][rDst] = ((p >> 22) ); - rgba[i][gDst] = ((p >> 12) & 0x3ff); - rgba[i][bDst] = ((p >> 2) & 0x3ff); - rgba[i][aDst] = ((p ) & 0x3 ); - } - } - break; - case GL_UNSIGNED_INT_2_10_10_10_REV: - if (swapBytes) { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - SWAP4BYTE(p); - rgba[i][rDst] = ((p ) & 0x3ff); - rgba[i][gDst] = ((p >> 10) & 0x3ff); - rgba[i][bDst] = ((p >> 20) & 0x3ff); - rgba[i][aDst] = ((p >> 30) ); - } - } - else { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - rgba[i][rDst] = ((p ) & 0x3ff); - rgba[i][gDst] = ((p >> 10) & 0x3ff); - rgba[i][bDst] = ((p >> 20) & 0x3ff); - rgba[i][aDst] = ((p >> 30) ); - } - } - break; - case GL_UNSIGNED_INT_5_9_9_9_REV: - if (swapBytes) { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - float f[3]; - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - SWAP4BYTE(p); - rgb9e5_to_float3(p, f); - rgba[i][rDst] = clamp_float_to_uint(f[0]); - rgba[i][gDst] = clamp_float_to_uint(f[1]); - rgba[i][bDst] = clamp_float_to_uint(f[2]); - rgba[i][aDst] = 1; - } - } - else { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - float f[3]; - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - rgb9e5_to_float3(p, f); - rgba[i][rDst] = clamp_float_to_uint(f[0]); - rgba[i][gDst] = clamp_float_to_uint(f[1]); - rgba[i][bDst] = clamp_float_to_uint(f[2]); - rgba[i][aDst] = 1; - } - } - break; - case GL_UNSIGNED_INT_10F_11F_11F_REV: - if (swapBytes) { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - float f[3]; - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - SWAP4BYTE(p); - r11g11b10f_to_float3(p, f); - rgba[i][rDst] = clamp_float_to_uint(f[0]); - rgba[i][gDst] = clamp_float_to_uint(f[1]); - rgba[i][bDst] = clamp_float_to_uint(f[2]); - rgba[i][aDst] = 1; - } - } - else { - const GLuint *uisrc = (const GLuint *) src; - GLuint i; - float f[3]; - for (i = 0; i < n; i ++) { - GLuint p = uisrc[i]; - r11g11b10f_to_float3(p, f); - rgba[i][rDst] = clamp_float_to_uint(f[0]); - rgba[i][gDst] = clamp_float_to_uint(f[1]); - rgba[i][bDst] = clamp_float_to_uint(f[2]); - rgba[i][aDst] = 1; - } - } - break; - default: - _mesa_problem(NULL, "bad srcType in extract uint data"); - break; - } -#undef PROCESS -} - - - -/* - * Unpack a row of color image data from a client buffer according to - * the pixel unpacking parameters. - * Return GLchan values in the specified dest image format. - * This is used by glDrawPixels and glTexImage?D(). - * \param ctx - the context - * n - number of pixels in the span - * dstFormat - format of destination color array - * dest - the destination color array - * srcFormat - source image format - * srcType - source image data type - * source - source image pointer - * srcPacking - pixel unpacking parameters - * transferOps - bitmask of IMAGE_*_BIT values of operations to apply - * - * XXX perhaps expand this to process whole images someday. - */ -void -_mesa_unpack_color_span_chan( struct gl_context *ctx, - GLuint n, GLenum dstFormat, GLchan dest[], - GLenum srcFormat, GLenum srcType, - const GLvoid *source, - const struct gl_pixelstore_attrib *srcPacking, - GLbitfield transferOps ) -{ - ASSERT(dstFormat == GL_ALPHA || - dstFormat == GL_LUMINANCE || - dstFormat == GL_LUMINANCE_ALPHA || - dstFormat == GL_INTENSITY || - dstFormat == GL_RED || - dstFormat == GL_RG || - dstFormat == GL_RGB || - dstFormat == GL_RGBA || - dstFormat == GL_COLOR_INDEX); - - ASSERT(srcFormat == GL_RED || - srcFormat == GL_GREEN || - srcFormat == GL_BLUE || - srcFormat == GL_ALPHA || - srcFormat == GL_LUMINANCE || - srcFormat == GL_LUMINANCE_ALPHA || - srcFormat == GL_INTENSITY || - srcFormat == GL_RG || - srcFormat == GL_RGB || - srcFormat == GL_BGR || - srcFormat == GL_RGBA || - srcFormat == GL_BGRA || - srcFormat == GL_ABGR_EXT || - srcFormat == GL_COLOR_INDEX); - - ASSERT(srcType == GL_BITMAP || - srcType == GL_UNSIGNED_BYTE || - srcType == GL_BYTE || - srcType == GL_UNSIGNED_SHORT || - srcType == GL_SHORT || - srcType == GL_UNSIGNED_INT || - srcType == GL_INT || - srcType == GL_HALF_FLOAT_ARB || - srcType == GL_FLOAT || - srcType == GL_UNSIGNED_BYTE_3_3_2 || - srcType == GL_UNSIGNED_BYTE_2_3_3_REV || - srcType == GL_UNSIGNED_SHORT_5_6_5 || - srcType == GL_UNSIGNED_SHORT_5_6_5_REV || - srcType == GL_UNSIGNED_SHORT_4_4_4_4 || - srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV || - srcType == GL_UNSIGNED_SHORT_5_5_5_1 || - srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV || - srcType == GL_UNSIGNED_INT_8_8_8_8 || - srcType == GL_UNSIGNED_INT_8_8_8_8_REV || - srcType == GL_UNSIGNED_INT_10_10_10_2 || - srcType == GL_UNSIGNED_INT_2_10_10_10_REV || - srcType == GL_UNSIGNED_INT_5_9_9_9_REV || - srcType == GL_UNSIGNED_INT_10F_11F_11F_REV); - - /* Try simple cases first */ - if (transferOps == 0) { - if (srcType == CHAN_TYPE) { - if (dstFormat == GL_RGBA) { - if (srcFormat == GL_RGBA) { - memcpy( dest, source, n * 4 * sizeof(GLchan) ); - return; - } - else if (srcFormat == GL_RGB) { - GLuint i; - const GLchan *src = (const GLchan *) source; - GLchan *dst = dest; - for (i = 0; i < n; i++) { - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; - dst[3] = CHAN_MAX; - src += 3; - dst += 4; - } - return; - } - } - else if (dstFormat == GL_RGB) { - if (srcFormat == GL_RGB) { - memcpy( dest, source, n * 3 * sizeof(GLchan) ); - return; - } - else if (srcFormat == GL_RGBA) { - GLuint i; - const GLchan *src = (const GLchan *) source; - GLchan *dst = dest; - for (i = 0; i < n; i++) { - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; - src += 4; - dst += 3; - } - return; - } - } - else if (dstFormat == srcFormat) { - GLint comps = _mesa_components_in_format(srcFormat); - assert(comps > 0); - memcpy( dest, source, n * comps * sizeof(GLchan) ); - return; - } - } - /* - * Common situation, loading 8bit RGBA/RGB source images - * into 16/32 bit destination. (OSMesa16/32) - */ - else if (srcType == GL_UNSIGNED_BYTE) { - if (dstFormat == GL_RGBA) { - if (srcFormat == GL_RGB) { - GLuint i; - const GLubyte *src = (const GLubyte *) source; - GLchan *dst = dest; - for (i = 0; i < n; i++) { - dst[0] = UBYTE_TO_CHAN(src[0]); - dst[1] = UBYTE_TO_CHAN(src[1]); - dst[2] = UBYTE_TO_CHAN(src[2]); - dst[3] = CHAN_MAX; - src += 3; - dst += 4; - } - return; - } - else if (srcFormat == GL_RGBA) { - GLuint i; - const GLubyte *src = (const GLubyte *) source; - GLchan *dst = dest; - for (i = 0; i < n; i++) { - dst[0] = UBYTE_TO_CHAN(src[0]); - dst[1] = UBYTE_TO_CHAN(src[1]); - dst[2] = UBYTE_TO_CHAN(src[2]); - dst[3] = UBYTE_TO_CHAN(src[3]); - src += 4; - dst += 4; - } - return; - } - } - else if (dstFormat == GL_RGB) { - if (srcFormat == GL_RGB) { - GLuint i; - const GLubyte *src = (const GLubyte *) source; - GLchan *dst = dest; - for (i = 0; i < n; i++) { - dst[0] = UBYTE_TO_CHAN(src[0]); - dst[1] = UBYTE_TO_CHAN(src[1]); - dst[2] = UBYTE_TO_CHAN(src[2]); - src += 3; - dst += 3; - } - return; - } - else if (srcFormat == GL_RGBA) { - GLuint i; - const GLubyte *src = (const GLubyte *) source; - GLchan *dst = dest; - for (i = 0; i < n; i++) { - dst[0] = UBYTE_TO_CHAN(src[0]); - dst[1] = UBYTE_TO_CHAN(src[1]); - dst[2] = UBYTE_TO_CHAN(src[2]); - src += 4; - dst += 3; - } - return; - } - } - } - } - - - /* general solution begins here */ - { - GLint dstComponents; - GLint rDst, gDst, bDst, aDst, lDst, iDst; - GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat)); - - if (!rgba) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); - return; - } - - dstComponents = _mesa_components_in_format( dstFormat ); - /* source & dest image formats should have been error checked by now */ - assert(dstComponents > 0); - - /* - * Extract image data and convert to RGBA floats - */ - if (srcFormat == GL_COLOR_INDEX) { - GLuint *indexes = (GLuint *) malloc(n * sizeof(GLuint)); - - if (!indexes) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); - return; - } - - extract_uint_indexes(n, indexes, srcFormat, srcType, source, - srcPacking); - - if (dstFormat == GL_COLOR_INDEX) { - GLuint i; - _mesa_apply_ci_transfer_ops(ctx, transferOps, n, indexes); - /* convert to GLchan and return */ - for (i = 0; i < n; i++) { - dest[i] = (GLchan) (indexes[i] & 0xff); - } - free(indexes); - free(rgba); - return; - } - else { - /* Convert indexes to RGBA */ - if (transferOps & IMAGE_SHIFT_OFFSET_BIT) { - _mesa_shift_and_offset_ci(ctx, n, indexes); - } - _mesa_map_ci_to_rgba(ctx, n, indexes, rgba); - } - - /* Don't do RGBA scale/bias or RGBA->RGBA mapping if starting - * with color indexes. - */ - transferOps &= ~(IMAGE_SCALE_BIAS_BIT | IMAGE_MAP_COLOR_BIT); - - free(indexes); - } - else { - /* non-color index data */ - extract_float_rgba(n, rgba, srcFormat, srcType, source, - srcPacking->SwapBytes); - } - - /* Need to clamp if returning GLubytes or GLushorts */ -#if CHAN_TYPE != GL_FLOAT - transferOps |= IMAGE_CLAMP_BIT; -#endif - - if (transferOps) { - _mesa_apply_rgba_transfer_ops(ctx, transferOps, n, rgba); - } - - get_component_indexes(dstFormat, - &rDst, &gDst, &bDst, &aDst, &lDst, &iDst); - - /* Now return the GLchan data in the requested dstFormat */ - if (rDst >= 0) { - GLchan *dst = dest; - GLuint i; - for (i = 0; i < n; i++) { - CLAMPED_FLOAT_TO_CHAN(dst[rDst], rgba[i][RCOMP]); - dst += dstComponents; - } - } - - if (gDst >= 0) { - GLchan *dst = dest; - GLuint i; - for (i = 0; i < n; i++) { - CLAMPED_FLOAT_TO_CHAN(dst[gDst], rgba[i][GCOMP]); - dst += dstComponents; - } - } - - if (bDst >= 0) { - GLchan *dst = dest; - GLuint i; - for (i = 0; i < n; i++) { - CLAMPED_FLOAT_TO_CHAN(dst[bDst], rgba[i][BCOMP]); - dst += dstComponents; - } - } - - if (aDst >= 0) { - GLchan *dst = dest; - GLuint i; - for (i = 0; i < n; i++) { - CLAMPED_FLOAT_TO_CHAN(dst[aDst], rgba[i][ACOMP]); - dst += dstComponents; - } - } - - if (iDst >= 0) { - GLchan *dst = dest; - GLuint i; - assert(iDst == 0); - assert(dstComponents == 1); - for (i = 0; i < n; i++) { - /* Intensity comes from red channel */ - CLAMPED_FLOAT_TO_CHAN(dst[i], rgba[i][RCOMP]); - } - } - - if (lDst >= 0) { - GLchan *dst = dest; - GLuint i; - assert(lDst == 0); - for (i = 0; i < n; i++) { - /* Luminance comes from red channel */ - CLAMPED_FLOAT_TO_CHAN(dst[0], rgba[i][RCOMP]); - dst += dstComponents; - } - } - - free(rgba); - } -} - - -/** - * Same as _mesa_unpack_color_span_chan(), but return GLfloat data - * instead of GLchan. - */ -void -_mesa_unpack_color_span_float( struct gl_context *ctx, - GLuint n, GLenum dstFormat, GLfloat dest[], - GLenum srcFormat, GLenum srcType, - const GLvoid *source, - const struct gl_pixelstore_attrib *srcPacking, - GLbitfield transferOps ) -{ - ASSERT(dstFormat == GL_ALPHA || - dstFormat == GL_LUMINANCE || - dstFormat == GL_LUMINANCE_ALPHA || - dstFormat == GL_INTENSITY || - dstFormat == GL_RED || - dstFormat == GL_RG || - dstFormat == GL_RGB || - dstFormat == GL_RGBA || - dstFormat == GL_COLOR_INDEX); - - ASSERT(srcFormat == GL_RED || - srcFormat == GL_GREEN || - srcFormat == GL_BLUE || - srcFormat == GL_ALPHA || - srcFormat == GL_LUMINANCE || - srcFormat == GL_LUMINANCE_ALPHA || - srcFormat == GL_INTENSITY || - srcFormat == GL_RG || - srcFormat == GL_RGB || - srcFormat == GL_BGR || - srcFormat == GL_RGBA || - srcFormat == GL_BGRA || - srcFormat == GL_ABGR_EXT || - srcFormat == GL_RED_INTEGER_EXT || - srcFormat == GL_GREEN_INTEGER_EXT || - srcFormat == GL_BLUE_INTEGER_EXT || - srcFormat == GL_ALPHA_INTEGER_EXT || - srcFormat == GL_RGB_INTEGER_EXT || - srcFormat == GL_RGBA_INTEGER_EXT || - srcFormat == GL_BGR_INTEGER_EXT || - srcFormat == GL_BGRA_INTEGER_EXT || - srcFormat == GL_LUMINANCE_INTEGER_EXT || - srcFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT || - srcFormat == GL_COLOR_INDEX); - - ASSERT(srcType == GL_BITMAP || - srcType == GL_UNSIGNED_BYTE || - srcType == GL_BYTE || - srcType == GL_UNSIGNED_SHORT || - srcType == GL_SHORT || - srcType == GL_UNSIGNED_INT || - srcType == GL_INT || - srcType == GL_HALF_FLOAT_ARB || - srcType == GL_FLOAT || - srcType == GL_UNSIGNED_BYTE_3_3_2 || - srcType == GL_UNSIGNED_BYTE_2_3_3_REV || - srcType == GL_UNSIGNED_SHORT_5_6_5 || - srcType == GL_UNSIGNED_SHORT_5_6_5_REV || - srcType == GL_UNSIGNED_SHORT_4_4_4_4 || - srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV || - srcType == GL_UNSIGNED_SHORT_5_5_5_1 || - srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV || - srcType == GL_UNSIGNED_INT_8_8_8_8 || - srcType == GL_UNSIGNED_INT_8_8_8_8_REV || - srcType == GL_UNSIGNED_INT_10_10_10_2 || - srcType == GL_UNSIGNED_INT_2_10_10_10_REV || - srcType == GL_UNSIGNED_INT_5_9_9_9_REV || - srcType == GL_UNSIGNED_INT_10F_11F_11F_REV); - - /* general solution, no special cases, yet */ - { - GLint dstComponents; - GLint rDst, gDst, bDst, aDst, lDst, iDst; - GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat)); - - if (!rgba) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); - return; - } - - dstComponents = _mesa_components_in_format( dstFormat ); - /* source & dest image formats should have been error checked by now */ - assert(dstComponents > 0); - - /* - * Extract image data and convert to RGBA floats - */ - if (srcFormat == GL_COLOR_INDEX) { - GLuint *indexes = (GLuint *) malloc(n * sizeof(GLuint)); - - if (!indexes) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); - free(rgba); - return; - } - - extract_uint_indexes(n, indexes, srcFormat, srcType, source, - srcPacking); - - if (dstFormat == GL_COLOR_INDEX) { - GLuint i; - _mesa_apply_ci_transfer_ops(ctx, transferOps, n, indexes); - /* convert to GLchan and return */ - for (i = 0; i < n; i++) { - dest[i] = (GLchan) (indexes[i] & 0xff); - } - free(indexes); - free(rgba); - return; - } - else { - /* Convert indexes to RGBA */ - if (transferOps & IMAGE_SHIFT_OFFSET_BIT) { - _mesa_shift_and_offset_ci(ctx, n, indexes); - } - _mesa_map_ci_to_rgba(ctx, n, indexes, rgba); - } - - /* Don't do RGBA scale/bias or RGBA->RGBA mapping if starting - * with color indexes. - */ - transferOps &= ~(IMAGE_SCALE_BIAS_BIT | IMAGE_MAP_COLOR_BIT); - - free(indexes); - } - else { - /* non-color index data */ - extract_float_rgba(n, rgba, srcFormat, srcType, source, - srcPacking->SwapBytes); - } - - if (transferOps) { - _mesa_apply_rgba_transfer_ops(ctx, transferOps, n, rgba); - } - - get_component_indexes(dstFormat, - &rDst, &gDst, &bDst, &aDst, &lDst, &iDst); - - /* Now pack results in the requested dstFormat */ - if (rDst >= 0) { - GLfloat *dst = dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[rDst] = rgba[i][RCOMP]; - dst += dstComponents; - } - } - - if (gDst >= 0) { - GLfloat *dst = dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[gDst] = rgba[i][GCOMP]; - dst += dstComponents; - } - } - - if (bDst >= 0) { - GLfloat *dst = dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[bDst] = rgba[i][BCOMP]; - dst += dstComponents; - } - } - - if (aDst >= 0) { - GLfloat *dst = dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[aDst] = rgba[i][ACOMP]; - dst += dstComponents; - } - } - - if (iDst >= 0) { - GLfloat *dst = dest; - GLuint i; - assert(iDst == 0); - assert(dstComponents == 1); - for (i = 0; i < n; i++) { - /* Intensity comes from red channel */ - dst[i] = rgba[i][RCOMP]; - } - } - - if (lDst >= 0) { - GLfloat *dst = dest; - GLuint i; - assert(lDst == 0); - for (i = 0; i < n; i++) { - /* Luminance comes from red channel */ - dst[0] = rgba[i][RCOMP]; - dst += dstComponents; - } - } - - free(rgba); - } -} - - -/** - * Same as _mesa_unpack_color_span_chan(), but return GLuint data - * instead of GLchan. - * No pixel transfer ops are applied. - */ -void -_mesa_unpack_color_span_uint(struct gl_context *ctx, - GLuint n, GLenum dstFormat, GLuint *dest, - GLenum srcFormat, GLenum srcType, - const GLvoid *source, - const struct gl_pixelstore_attrib *srcPacking) -{ - GLuint (*rgba)[4] = (GLuint (*)[4]) malloc(n * 4 * sizeof(GLfloat)); - - if (!rgba) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); - return; - } - - ASSERT(dstFormat == GL_ALPHA || - dstFormat == GL_LUMINANCE || - dstFormat == GL_LUMINANCE_ALPHA || - dstFormat == GL_INTENSITY || - dstFormat == GL_RED || - dstFormat == GL_RG || - dstFormat == GL_RGB || - dstFormat == GL_RGBA); - - ASSERT(srcFormat == GL_RED || - srcFormat == GL_GREEN || - srcFormat == GL_BLUE || - srcFormat == GL_ALPHA || - srcFormat == GL_LUMINANCE || - srcFormat == GL_LUMINANCE_ALPHA || - srcFormat == GL_INTENSITY || - srcFormat == GL_RG || - srcFormat == GL_RGB || - srcFormat == GL_BGR || - srcFormat == GL_RGBA || - srcFormat == GL_BGRA || - srcFormat == GL_ABGR_EXT || - srcFormat == GL_RED_INTEGER_EXT || - srcFormat == GL_GREEN_INTEGER_EXT || - srcFormat == GL_BLUE_INTEGER_EXT || - srcFormat == GL_ALPHA_INTEGER_EXT || - srcFormat == GL_RGB_INTEGER_EXT || - srcFormat == GL_RGBA_INTEGER_EXT || - srcFormat == GL_BGR_INTEGER_EXT || - srcFormat == GL_BGRA_INTEGER_EXT || - srcFormat == GL_LUMINANCE_INTEGER_EXT || - srcFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT); - - ASSERT(srcType == GL_UNSIGNED_BYTE || - srcType == GL_BYTE || - srcType == GL_UNSIGNED_SHORT || - srcType == GL_SHORT || - srcType == GL_UNSIGNED_INT || - srcType == GL_INT || - srcType == GL_HALF_FLOAT_ARB || - srcType == GL_FLOAT || - srcType == GL_UNSIGNED_BYTE_3_3_2 || - srcType == GL_UNSIGNED_BYTE_2_3_3_REV || - srcType == GL_UNSIGNED_SHORT_5_6_5 || - srcType == GL_UNSIGNED_SHORT_5_6_5_REV || - srcType == GL_UNSIGNED_SHORT_4_4_4_4 || - srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV || - srcType == GL_UNSIGNED_SHORT_5_5_5_1 || - srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV || - srcType == GL_UNSIGNED_INT_8_8_8_8 || - srcType == GL_UNSIGNED_INT_8_8_8_8_REV || - srcType == GL_UNSIGNED_INT_10_10_10_2 || - srcType == GL_UNSIGNED_INT_2_10_10_10_REV || - srcType == GL_UNSIGNED_INT_5_9_9_9_REV || - srcType == GL_UNSIGNED_INT_10F_11F_11F_REV); - - - /* Extract image data as uint[4] pixels */ - extract_uint_rgba(n, rgba, srcFormat, srcType, source, - srcPacking->SwapBytes); - - if (dstFormat == GL_RGBA) { - /* simple case */ - memcpy(dest, rgba, 4 * sizeof(GLuint) * n); - } - else { - /* general case */ - GLint rDst, gDst, bDst, aDst, lDst, iDst; - GLint dstComponents = _mesa_components_in_format( dstFormat ); - - assert(dstComponents > 0); - - get_component_indexes(dstFormat, - &rDst, &gDst, &bDst, &aDst, &lDst, &iDst); - - /* Now pack values in the requested dest format */ - if (rDst >= 0) { - GLuint *dst = dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[rDst] = rgba[i][RCOMP]; - dst += dstComponents; - } - } - - if (gDst >= 0) { - GLuint *dst = dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[gDst] = rgba[i][GCOMP]; - dst += dstComponents; - } - } - - if (bDst >= 0) { - GLuint *dst = dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[bDst] = rgba[i][BCOMP]; - dst += dstComponents; - } - } - - if (aDst >= 0) { - GLuint *dst = dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[aDst] = rgba[i][ACOMP]; - dst += dstComponents; - } - } - - if (iDst >= 0) { - GLuint *dst = dest; - GLuint i; - assert(iDst == 0); - assert(dstComponents == 1); - for (i = 0; i < n; i++) { - /* Intensity comes from red channel */ - dst[i] = rgba[i][RCOMP]; - } - } - - if (lDst >= 0) { - GLuint *dst = dest; - GLuint i; - assert(lDst == 0); - for (i = 0; i < n; i++) { - /* Luminance comes from red channel */ - dst[0] = rgba[i][RCOMP]; - dst += dstComponents; - } - } - } - - free(rgba); -} - - - -/** - * Similar to _mesa_unpack_color_span_float(), but for dudv data instead of rgba, - * directly return GLbyte data, no transfer ops apply. - */ -void -_mesa_unpack_dudv_span_byte( struct gl_context *ctx, - GLuint n, GLenum dstFormat, GLbyte dest[], - GLenum srcFormat, GLenum srcType, - const GLvoid *source, - const struct gl_pixelstore_attrib *srcPacking, - GLbitfield transferOps ) -{ - ASSERT(dstFormat == GL_DUDV_ATI); - ASSERT(srcFormat == GL_DUDV_ATI || - srcFormat == GL_DU8DV8_ATI); - - ASSERT(srcType == GL_UNSIGNED_BYTE || - srcType == GL_BYTE || - srcType == GL_UNSIGNED_SHORT || - srcType == GL_SHORT || - srcType == GL_UNSIGNED_INT || - srcType == GL_INT || - srcType == GL_HALF_FLOAT_ARB || - srcType == GL_FLOAT); - - /* general solution */ - { - GLint dstComponents; - GLbyte *dst = dest; - GLuint i; - GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat)); - - if (!rgba) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); - return; - } - - dstComponents = _mesa_components_in_format( dstFormat ); - /* source & dest image formats should have been error checked by now */ - assert(dstComponents > 0); - - /* - * Extract image data and convert to RGBA floats - */ - extract_float_rgba(n, rgba, srcFormat, srcType, source, - srcPacking->SwapBytes); - - - /* Now determine which color channels we need to produce. - * And determine the dest index (offset) within each color tuple. - */ - - /* Now pack results in the requested dstFormat */ - for (i = 0; i < n; i++) { - /* not sure - need clamp[-1,1] here? */ - dst[0] = FLOAT_TO_BYTE(rgba[i][RCOMP]); - dst[1] = FLOAT_TO_BYTE(rgba[i][GCOMP]); - dst += dstComponents; - } - - free(rgba); - } -} - -/* - * Unpack a row of color index data from a client buffer according to - * the pixel unpacking parameters. - * This is (or will be) used by glDrawPixels, glTexImage[123]D, etc. - * - * Args: ctx - the context - * n - number of pixels - * dstType - destination data type - * dest - destination array - * srcType - source pixel type - * source - source data pointer - * srcPacking - pixel unpacking parameters - * transferOps - the pixel transfer operations to apply - */ -void -_mesa_unpack_index_span( struct gl_context *ctx, GLuint n, - GLenum dstType, GLvoid *dest, - GLenum srcType, const GLvoid *source, - const struct gl_pixelstore_attrib *srcPacking, - GLbitfield transferOps ) -{ - ASSERT(srcType == GL_BITMAP || - srcType == GL_UNSIGNED_BYTE || - srcType == GL_BYTE || - srcType == GL_UNSIGNED_SHORT || - srcType == GL_SHORT || - srcType == GL_UNSIGNED_INT || - srcType == GL_INT || - srcType == GL_HALF_FLOAT_ARB || - srcType == GL_FLOAT); - - ASSERT(dstType == GL_UNSIGNED_BYTE || - dstType == GL_UNSIGNED_SHORT || - dstType == GL_UNSIGNED_INT); - - - transferOps &= (IMAGE_MAP_COLOR_BIT | IMAGE_SHIFT_OFFSET_BIT); - - /* - * Try simple cases first - */ - if (transferOps == 0 && srcType == GL_UNSIGNED_BYTE - && dstType == GL_UNSIGNED_BYTE) { - memcpy(dest, source, n * sizeof(GLubyte)); - } - else if (transferOps == 0 && srcType == GL_UNSIGNED_INT - && dstType == GL_UNSIGNED_INT && !srcPacking->SwapBytes) { - memcpy(dest, source, n * sizeof(GLuint)); - } - else { - /* - * general solution - */ - GLuint *indexes = (GLuint *) malloc(n * sizeof(GLuint)); - - if (!indexes) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); - return; - } - - extract_uint_indexes(n, indexes, GL_COLOR_INDEX, srcType, source, - srcPacking); - - if (transferOps) - _mesa_apply_ci_transfer_ops(ctx, transferOps, n, indexes); - - /* convert to dest type */ - switch (dstType) { - case GL_UNSIGNED_BYTE: - { - GLubyte *dst = (GLubyte *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = (GLubyte) (indexes[i] & 0xff); - } - } - break; - case GL_UNSIGNED_SHORT: - { - GLuint *dst = (GLuint *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = (GLushort) (indexes[i] & 0xffff); - } - } - break; - case GL_UNSIGNED_INT: - memcpy(dest, indexes, n * sizeof(GLuint)); - break; - default: - _mesa_problem(ctx, "bad dstType in _mesa_unpack_index_span"); - } - - free(indexes); - } -} - - -void -_mesa_pack_index_span( struct gl_context *ctx, GLuint n, - GLenum dstType, GLvoid *dest, const GLuint *source, - const struct gl_pixelstore_attrib *dstPacking, - GLbitfield transferOps ) -{ - GLuint *indexes = (GLuint *) malloc(n * sizeof(GLuint)); - - if (!indexes) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel packing"); - return; - } - - transferOps &= (IMAGE_MAP_COLOR_BIT | IMAGE_SHIFT_OFFSET_BIT); - - if (transferOps & (IMAGE_MAP_COLOR_BIT | IMAGE_SHIFT_OFFSET_BIT)) { - /* make a copy of input */ - memcpy(indexes, source, n * sizeof(GLuint)); - _mesa_apply_ci_transfer_ops(ctx, transferOps, n, indexes); - source = indexes; - } - - switch (dstType) { - case GL_UNSIGNED_BYTE: - { - GLubyte *dst = (GLubyte *) dest; - GLuint i; - for (i = 0; i < n; i++) { - *dst++ = (GLubyte) source[i]; - } - } - break; - case GL_BYTE: - { - GLbyte *dst = (GLbyte *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = (GLbyte) source[i]; - } - } - break; - case GL_UNSIGNED_SHORT: - { - GLushort *dst = (GLushort *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = (GLushort) source[i]; - } - if (dstPacking->SwapBytes) { - _mesa_swap2( (GLushort *) dst, n ); - } - } - break; - case GL_SHORT: - { - GLshort *dst = (GLshort *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = (GLshort) source[i]; - } - if (dstPacking->SwapBytes) { - _mesa_swap2( (GLushort *) dst, n ); - } - } - break; - case GL_UNSIGNED_INT: - { - GLuint *dst = (GLuint *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = (GLuint) source[i]; - } - if (dstPacking->SwapBytes) { - _mesa_swap4( (GLuint *) dst, n ); - } - } - break; - case GL_INT: - { - GLint *dst = (GLint *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = (GLint) source[i]; - } - if (dstPacking->SwapBytes) { - _mesa_swap4( (GLuint *) dst, n ); - } - } - break; - case GL_FLOAT: - { - GLfloat *dst = (GLfloat *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = (GLfloat) source[i]; - } - if (dstPacking->SwapBytes) { - _mesa_swap4( (GLuint *) dst, n ); - } - } - break; - case GL_HALF_FLOAT_ARB: - { - GLhalfARB *dst = (GLhalfARB *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = _mesa_float_to_half((GLfloat) source[i]); - } - if (dstPacking->SwapBytes) { - _mesa_swap2( (GLushort *) dst, n ); - } - } - break; - default: - _mesa_problem(ctx, "bad type in _mesa_pack_index_span"); - } - - free(indexes); -} - - -/* - * Unpack a row of stencil data from a client buffer according to - * the pixel unpacking parameters. - * This is (or will be) used by glDrawPixels - * - * Args: ctx - the context - * n - number of pixels - * dstType - destination data type - * dest - destination array - * srcType - source pixel type - * source - source data pointer - * srcPacking - pixel unpacking parameters - * transferOps - apply offset/bias/lookup ops? - */ -void -_mesa_unpack_stencil_span( struct gl_context *ctx, GLuint n, - GLenum dstType, GLvoid *dest, - GLenum srcType, const GLvoid *source, - const struct gl_pixelstore_attrib *srcPacking, - GLbitfield transferOps ) -{ - ASSERT(srcType == GL_BITMAP || - srcType == GL_UNSIGNED_BYTE || - srcType == GL_BYTE || - srcType == GL_UNSIGNED_SHORT || - srcType == GL_SHORT || - srcType == GL_UNSIGNED_INT || - srcType == GL_INT || - srcType == GL_UNSIGNED_INT_24_8_EXT || - srcType == GL_HALF_FLOAT_ARB || - srcType == GL_FLOAT); - - ASSERT(dstType == GL_UNSIGNED_BYTE || - dstType == GL_UNSIGNED_SHORT || - dstType == GL_UNSIGNED_INT); - - /* only shift and offset apply to stencil */ - transferOps &= IMAGE_SHIFT_OFFSET_BIT; - - /* - * Try simple cases first - */ - if (transferOps == 0 && - !ctx->Pixel.MapStencilFlag && - srcType == GL_UNSIGNED_BYTE && - dstType == GL_UNSIGNED_BYTE) { - memcpy(dest, source, n * sizeof(GLubyte)); - } - else if (transferOps == 0 && - !ctx->Pixel.MapStencilFlag && - srcType == GL_UNSIGNED_INT && - dstType == GL_UNSIGNED_INT && - !srcPacking->SwapBytes) { - memcpy(dest, source, n * sizeof(GLuint)); - } - else { - /* - * general solution - */ - GLuint *indexes = (GLuint *) malloc(n * sizeof(GLuint)); - - if (!indexes) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "stencil unpacking"); - return; - } - - extract_uint_indexes(n, indexes, GL_STENCIL_INDEX, srcType, source, - srcPacking); - - if (transferOps & IMAGE_SHIFT_OFFSET_BIT) { - /* shift and offset indexes */ - _mesa_shift_and_offset_ci(ctx, n, indexes); - } - - if (ctx->Pixel.MapStencilFlag) { - /* Apply stencil lookup table */ - const GLuint mask = ctx->PixelMaps.StoS.Size - 1; - GLuint i; - for (i = 0; i < n; i++) { - indexes[i] = (GLuint)ctx->PixelMaps.StoS.Map[ indexes[i] & mask ]; - } - } - - /* convert to dest type */ - switch (dstType) { - case GL_UNSIGNED_BYTE: - { - GLubyte *dst = (GLubyte *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = (GLubyte) (indexes[i] & 0xff); - } - } - break; - case GL_UNSIGNED_SHORT: - { - GLuint *dst = (GLuint *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = (GLushort) (indexes[i] & 0xffff); - } - } - break; - case GL_UNSIGNED_INT: - memcpy(dest, indexes, n * sizeof(GLuint)); - break; - default: - _mesa_problem(ctx, "bad dstType in _mesa_unpack_stencil_span"); - } - - free(indexes); - } -} - - -void -_mesa_pack_stencil_span( struct gl_context *ctx, GLuint n, - GLenum dstType, GLvoid *dest, const GLstencil *source, - const struct gl_pixelstore_attrib *dstPacking ) -{ - GLstencil *stencil = (GLstencil *) malloc(n * sizeof(GLstencil)); - - if (!stencil) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "stencil packing"); - return; - } - - if (ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset || - ctx->Pixel.MapStencilFlag) { - /* make a copy of input */ - memcpy(stencil, source, n * sizeof(GLstencil)); - _mesa_apply_stencil_transfer_ops(ctx, n, stencil); - source = stencil; - } - - switch (dstType) { - case GL_UNSIGNED_BYTE: - if (sizeof(GLstencil) == 1) { - memcpy( dest, source, n ); - } - else { - GLubyte *dst = (GLubyte *) dest; - GLuint i; - for (i=0;iSwapBytes) { - _mesa_swap2( (GLushort *) dst, n ); - } - } - break; - case GL_SHORT: - { - GLshort *dst = (GLshort *) dest; - GLuint i; - for (i=0;iSwapBytes) { - _mesa_swap2( (GLushort *) dst, n ); - } - } - break; - case GL_UNSIGNED_INT: - { - GLuint *dst = (GLuint *) dest; - GLuint i; - for (i=0;iSwapBytes) { - _mesa_swap4( (GLuint *) dst, n ); - } - } - break; - case GL_INT: - { - GLint *dst = (GLint *) dest; - GLuint i; - for (i=0;iSwapBytes) { - _mesa_swap4( (GLuint *) dst, n ); - } - } - break; - case GL_FLOAT: - { - GLfloat *dst = (GLfloat *) dest; - GLuint i; - for (i=0;iSwapBytes) { - _mesa_swap4( (GLuint *) dst, n ); - } - } - break; - case GL_HALF_FLOAT_ARB: - { - GLhalfARB *dst = (GLhalfARB *) dest; - GLuint i; - for (i=0;iSwapBytes) { - _mesa_swap2( (GLushort *) dst, n ); - } - } - break; - case GL_BITMAP: - if (dstPacking->LsbFirst) { - GLubyte *dst = (GLubyte *) dest; - GLint shift = 0; - GLuint i; - for (i = 0; i < n; i++) { - if (shift == 0) - *dst = 0; - *dst |= ((source[i] != 0) << shift); - shift++; - if (shift == 8) { - shift = 0; - dst++; - } - } - } - else { - GLubyte *dst = (GLubyte *) dest; - GLint shift = 7; - GLuint i; - for (i = 0; i < n; i++) { - if (shift == 7) - *dst = 0; - *dst |= ((source[i] != 0) << shift); - shift--; - if (shift < 0) { - shift = 7; - dst++; - } - } - } - break; - default: - _mesa_problem(ctx, "bad type in _mesa_pack_index_span"); - } - - free(stencil); -} - -#define DEPTH_VALUES(GLTYPE, GLTYPE2FLOAT) \ - do { \ - GLuint i; \ - const GLTYPE *src = (const GLTYPE *)source; \ - for (i = 0; i < n; i++) { \ - GLTYPE value = src[i]; \ - if (srcPacking->SwapBytes) { \ - if (sizeof(GLTYPE) == 2) { \ - SWAP2BYTE(value); \ - } else if (sizeof(GLTYPE) == 4) { \ - SWAP4BYTE(value); \ - } \ - } \ - depthValues[i] = GLTYPE2FLOAT(value); \ - } \ - } while (0) - - -/** - * Unpack a row of depth/z values from memory, returning GLushort, GLuint - * or GLfloat values. - * The glPixelTransfer (scale/bias) params will be applied. - * - * \param dstType one of GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, GL_FLOAT - * \param depthMax max value for returned GLushort or GLuint values - * (ignored for GLfloat). - */ -void -_mesa_unpack_depth_span( struct gl_context *ctx, GLuint n, - GLenum dstType, GLvoid *dest, GLuint depthMax, - GLenum srcType, const GLvoid *source, - const struct gl_pixelstore_attrib *srcPacking ) -{ - GLfloat *depthTemp, *depthValues; - GLboolean needClamp = GL_FALSE; - - /* Look for special cases first. - * Not only are these faster, they're less prone to numeric conversion - * problems. Otherwise, converting from an int type to a float then - * back to an int type can introduce errors that will show up as - * artifacts in things like depth peeling which uses glCopyTexImage. - */ - if (ctx->Pixel.DepthScale == 1.0 && ctx->Pixel.DepthBias == 0.0) { - if (srcType == GL_UNSIGNED_INT && dstType == GL_UNSIGNED_SHORT) { - const GLuint *src = (const GLuint *) source; - GLushort *dst = (GLushort *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = src[i] >> 16; - } - return; - } - if (srcType == GL_UNSIGNED_SHORT - && dstType == GL_UNSIGNED_INT - && depthMax == 0xffffffff) { - const GLushort *src = (const GLushort *) source; - GLuint *dst = (GLuint *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = src[i] | (src[i] << 16); - } - return; - } - if (srcType == GL_UNSIGNED_INT_24_8 - && dstType == GL_UNSIGNED_INT - && depthMax == 0xffffff) { - const GLuint *src = (const GLuint *) source; - GLuint *dst = (GLuint *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = src[i] >> 8; - } - return; - } - /* XXX may want to add additional cases here someday */ - } - - /* general case path follows */ - - depthTemp = (GLfloat *) malloc(n * sizeof(GLfloat)); - if (!depthTemp) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); - return; - } - - if (dstType == GL_FLOAT) { - depthValues = (GLfloat *) dest; - } - else { - depthValues = depthTemp; - } - - /* Convert incoming values to GLfloat. Some conversions will require - * clamping, below. - */ - switch (srcType) { - case GL_BYTE: - DEPTH_VALUES(GLbyte, BYTE_TO_FLOAT); - needClamp = GL_TRUE; - break; - case GL_UNSIGNED_BYTE: - DEPTH_VALUES(GLubyte, UBYTE_TO_FLOAT); - break; - case GL_SHORT: - DEPTH_VALUES(GLshort, SHORT_TO_FLOAT); - needClamp = GL_TRUE; - break; - case GL_UNSIGNED_SHORT: - DEPTH_VALUES(GLushort, USHORT_TO_FLOAT); - break; - case GL_INT: - DEPTH_VALUES(GLint, INT_TO_FLOAT); - needClamp = GL_TRUE; - break; - case GL_UNSIGNED_INT: - DEPTH_VALUES(GLuint, UINT_TO_FLOAT); - break; - case GL_UNSIGNED_INT_24_8_EXT: /* GL_EXT_packed_depth_stencil */ - if (dstType == GL_UNSIGNED_INT_24_8_EXT && - depthMax == 0xffffff && - ctx->Pixel.DepthScale == 1.0 && - ctx->Pixel.DepthBias == 0.0) { - const GLuint *src = (const GLuint *) source; - GLuint *zValues = (GLuint *) dest; - GLuint i; - for (i = 0; i < n; i++) { - GLuint value = src[i]; - if (srcPacking->SwapBytes) { - SWAP4BYTE(value); - } - zValues[i] = value & 0xffffff00; - } - return; - } - else { - const GLuint *src = (const GLuint *) source; - const GLfloat scale = 1.0f / 0xffffff; - GLuint i; - for (i = 0; i < n; i++) { - GLuint value = src[i]; - if (srcPacking->SwapBytes) { - SWAP4BYTE(value); - } - depthValues[i] = (value >> 8) * scale; - } - } - break; - case GL_FLOAT: - DEPTH_VALUES(GLfloat, 1*); - needClamp = GL_TRUE; - break; - case GL_HALF_FLOAT_ARB: - { - GLuint i; - const GLhalfARB *src = (const GLhalfARB *) source; - for (i = 0; i < n; i++) { - GLhalfARB value = src[i]; - if (srcPacking->SwapBytes) { - SWAP2BYTE(value); - } - depthValues[i] = _mesa_half_to_float(value); - } - needClamp = GL_TRUE; - } - break; - default: - _mesa_problem(NULL, "bad type in _mesa_unpack_depth_span()"); - free(depthTemp); - return; - } - - /* apply depth scale and bias */ - { - const GLfloat scale = ctx->Pixel.DepthScale; - const GLfloat bias = ctx->Pixel.DepthBias; - if (scale != 1.0 || bias != 0.0) { - GLuint i; - for (i = 0; i < n; i++) { - depthValues[i] = depthValues[i] * scale + bias; - } - needClamp = GL_TRUE; - } - } - - /* clamp to [0, 1] */ - if (needClamp) { - GLuint i; - for (i = 0; i < n; i++) { - depthValues[i] = (GLfloat)CLAMP(depthValues[i], 0.0, 1.0); - } - } - - /* - * Convert values to dstType - */ - if (dstType == GL_UNSIGNED_INT) { - GLuint *zValues = (GLuint *) dest; - GLuint i; - if (depthMax <= 0xffffff) { - /* no overflow worries */ - for (i = 0; i < n; i++) { - zValues[i] = (GLuint) (depthValues[i] * (GLfloat) depthMax); - } - } - else { - /* need to use double precision to prevent overflow problems */ - for (i = 0; i < n; i++) { - GLdouble z = depthValues[i] * (GLfloat) depthMax; - if (z >= (GLdouble) 0xffffffff) - zValues[i] = 0xffffffff; - else - zValues[i] = (GLuint) z; - } - } - } - else if (dstType == GL_UNSIGNED_SHORT) { - GLushort *zValues = (GLushort *) dest; - GLuint i; - ASSERT(depthMax <= 0xffff); - for (i = 0; i < n; i++) { - zValues[i] = (GLushort) (depthValues[i] * (GLfloat) depthMax); - } - } - else { - ASSERT(dstType == GL_FLOAT); - /*ASSERT(depthMax == 1.0F);*/ - } - - free(depthTemp); -} - - -/* - * Pack an array of depth values. The values are floats in [0,1]. - */ -void -_mesa_pack_depth_span( struct gl_context *ctx, GLuint n, GLvoid *dest, - GLenum dstType, const GLfloat *depthSpan, - const struct gl_pixelstore_attrib *dstPacking ) -{ - GLfloat *depthCopy = (GLfloat *) malloc(n * sizeof(GLfloat)); - if (!depthCopy) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel packing"); - return; - } - - if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0) { - memcpy(depthCopy, depthSpan, n * sizeof(GLfloat)); - _mesa_scale_and_bias_depth(ctx, n, depthCopy); - depthSpan = depthCopy; - } - - switch (dstType) { - case GL_UNSIGNED_BYTE: - { - GLubyte *dst = (GLubyte *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = FLOAT_TO_UBYTE( depthSpan[i] ); - } - } - break; - case GL_BYTE: - { - GLbyte *dst = (GLbyte *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = FLOAT_TO_BYTE( depthSpan[i] ); - } - } - break; - case GL_UNSIGNED_SHORT: - { - GLushort *dst = (GLushort *) dest; - GLuint i; - for (i = 0; i < n; i++) { - CLAMPED_FLOAT_TO_USHORT(dst[i], depthSpan[i]); - } - if (dstPacking->SwapBytes) { - _mesa_swap2( (GLushort *) dst, n ); - } - } - break; - case GL_SHORT: - { - GLshort *dst = (GLshort *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = FLOAT_TO_SHORT( depthSpan[i] ); - } - if (dstPacking->SwapBytes) { - _mesa_swap2( (GLushort *) dst, n ); - } - } - break; - case GL_UNSIGNED_INT: - { - GLuint *dst = (GLuint *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = FLOAT_TO_UINT( depthSpan[i] ); - } - if (dstPacking->SwapBytes) { - _mesa_swap4( (GLuint *) dst, n ); - } - } - break; - case GL_INT: - { - GLint *dst = (GLint *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = FLOAT_TO_INT( depthSpan[i] ); - } - if (dstPacking->SwapBytes) { - _mesa_swap4( (GLuint *) dst, n ); - } - } - break; - case GL_FLOAT: - { - GLfloat *dst = (GLfloat *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = depthSpan[i]; - } - if (dstPacking->SwapBytes) { - _mesa_swap4( (GLuint *) dst, n ); - } - } - break; - case GL_HALF_FLOAT_ARB: - { - GLhalfARB *dst = (GLhalfARB *) dest; - GLuint i; - for (i = 0; i < n; i++) { - dst[i] = _mesa_float_to_half(depthSpan[i]); - } - if (dstPacking->SwapBytes) { - _mesa_swap2( (GLushort *) dst, n ); - } - } - break; - default: - _mesa_problem(ctx, "bad type in _mesa_pack_depth_span"); - } - - free(depthCopy); -} - - - -/** - * Pack depth and stencil values as GL_DEPTH_STENCIL/GL_UNSIGNED_INT_24_8. - */ -void -_mesa_pack_depth_stencil_span(struct gl_context *ctx, GLuint n, GLuint *dest, - const GLfloat *depthVals, - const GLstencil *stencilVals, - const struct gl_pixelstore_attrib *dstPacking) -{ - GLfloat *depthCopy = (GLfloat *) malloc(n * sizeof(GLfloat)); - GLstencil *stencilCopy = (GLstencil *) malloc(n * sizeof(GLstencil)); - GLuint i; - - if (!depthCopy || !stencilCopy) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel packing"); - free(depthCopy); - free(stencilCopy); - return; - } - - if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0) { - memcpy(depthCopy, depthVals, n * sizeof(GLfloat)); - _mesa_scale_and_bias_depth(ctx, n, depthCopy); - depthVals = depthCopy; - } - - if (ctx->Pixel.IndexShift || - ctx->Pixel.IndexOffset || - ctx->Pixel.MapStencilFlag) { - memcpy(stencilCopy, stencilVals, n * sizeof(GLstencil)); - _mesa_apply_stencil_transfer_ops(ctx, n, stencilCopy); - stencilVals = stencilCopy; - } - - for (i = 0; i < n; i++) { - GLuint z = (GLuint) (depthVals[i] * 0xffffff); - dest[i] = (z << 8) | (stencilVals[i] & 0xff); - } - - if (dstPacking->SwapBytes) { - _mesa_swap4(dest, n); - } - - free(depthCopy); - free(stencilCopy); -} - - - - -/** - * Unpack image data. Apply byte swapping, byte flipping (bitmap). - * Return all image data in a contiguous block. This is used when we - * compile glDrawPixels, glTexImage, etc into a display list. We - * need a copy of the data in a standard format. - */ -void * -_mesa_unpack_image( GLuint dimensions, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *pixels, - const struct gl_pixelstore_attrib *unpack ) -{ - GLint bytesPerRow, compsPerRow; - GLboolean flipBytes, swap2, swap4; - - if (!pixels) - return NULL; /* not necessarily an error */ - - if (width <= 0 || height <= 0 || depth <= 0) - return NULL; /* generate error later */ - - if (type == GL_BITMAP) { - bytesPerRow = (width + 7) >> 3; - flipBytes = unpack->LsbFirst; - swap2 = swap4 = GL_FALSE; - compsPerRow = 0; - } - else { - const GLint bytesPerPixel = _mesa_bytes_per_pixel(format, type); - GLint components = _mesa_components_in_format(format); - GLint bytesPerComp; - - if (_mesa_type_is_packed(type)) - components = 1; - - if (bytesPerPixel <= 0 || components <= 0) - return NULL; /* bad format or type. generate error later */ - bytesPerRow = bytesPerPixel * width; - bytesPerComp = bytesPerPixel / components; - flipBytes = GL_FALSE; - swap2 = (bytesPerComp == 2) && unpack->SwapBytes; - swap4 = (bytesPerComp == 4) && unpack->SwapBytes; - compsPerRow = components * width; - assert(compsPerRow >= width); - } - - { - GLubyte *destBuffer - = (GLubyte *) malloc(bytesPerRow * height * depth); - GLubyte *dst; - GLint img, row; - if (!destBuffer) - return NULL; /* generate GL_OUT_OF_MEMORY later */ - - dst = destBuffer; - for (img = 0; img < depth; img++) { - for (row = 0; row < height; row++) { - const GLvoid *src = _mesa_image_address(dimensions, unpack, pixels, - width, height, format, type, img, row, 0); - - if ((type == GL_BITMAP) && (unpack->SkipPixels & 0x7)) { - GLint i; - flipBytes = GL_FALSE; - if (unpack->LsbFirst) { - GLubyte srcMask = 1 << (unpack->SkipPixels & 0x7); - GLubyte dstMask = 128; - const GLubyte *s = src; - GLubyte *d = dst; - *d = 0; - for (i = 0; i < width; i++) { - if (*s & srcMask) { - *d |= dstMask; - } - if (srcMask == 128) { - srcMask = 1; - s++; - } - else { - srcMask = srcMask << 1; - } - if (dstMask == 1) { - dstMask = 128; - d++; - *d = 0; - } - else { - dstMask = dstMask >> 1; - } - } - } - else { - GLubyte srcMask = 128 >> (unpack->SkipPixels & 0x7); - GLubyte dstMask = 128; - const GLubyte *s = src; - GLubyte *d = dst; - *d = 0; - for (i = 0; i < width; i++) { - if (*s & srcMask) { - *d |= dstMask; - } - if (srcMask == 1) { - srcMask = 128; - s++; - } - else { - srcMask = srcMask >> 1; - } - if (dstMask == 1) { - dstMask = 128; - d++; - *d = 0; - } - else { - dstMask = dstMask >> 1; - } - } - } - } - else { - memcpy(dst, src, bytesPerRow); - } - - /* byte flipping/swapping */ - if (flipBytes) { - flip_bytes((GLubyte *) dst, bytesPerRow); - } - else if (swap2) { - _mesa_swap2((GLushort*) dst, compsPerRow); - } - else if (swap4) { - _mesa_swap4((GLuint*) dst, compsPerRow); - } - dst += bytesPerRow; - } - } - return destBuffer; - } -} - +/* + * Mesa 3-D graphics library + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009-2010 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THEA AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** + * \file pack.c + * Image and pixel span packing and unpacking. + */ + + +#include "glheader.h" +#include "colormac.h" +#include "enums.h" +#include "image.h" +#include "imports.h" +#include "mtypes.h" +#include "pack.h" +#include "pixeltransfer.h" +#include "imports.h" +#include "../../gallium/auxiliary/util/u_format_rgb9e5.h" +#include "../../gallium/auxiliary/util/u_format_r11g11b10f.h" + + +/** + * NOTE: + * Normally, BYTE_TO_FLOAT(0) returns 0.00392 That causes problems when + * we later convert the float to a packed integer value (such as for + * GL_RGB5_A1) because we'll wind up with a non-zero value. + * + * We redefine the macros here so zero is handled correctly. + */ +#undef BYTE_TO_FLOAT +#define BYTE_TO_FLOAT(B) ((B) == 0 ? 0.0F : ((2.0F * (B) + 1.0F) * (1.0F/255.0F))) + +#undef SHORT_TO_FLOAT +#define SHORT_TO_FLOAT(S) ((S) == 0 ? 0.0F : ((2.0F * (S) + 1.0F) * (1.0F/65535.0F))) + + + +/** Compute ceiling of integer quotient of A divided by B. */ +#define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 ) + + +/** + * Flip the 8 bits in each byte of the given array. + * + * \param p array. + * \param n number of bytes. + * + * \todo try this trick to flip bytes someday: + * \code + * v = ((v & 0x55555555) << 1) | ((v >> 1) & 0x55555555); + * v = ((v & 0x33333333) << 2) | ((v >> 2) & 0x33333333); + * v = ((v & 0x0f0f0f0f) << 4) | ((v >> 4) & 0x0f0f0f0f); + * \endcode + */ +static void +flip_bytes( GLubyte *p, GLuint n ) +{ + GLuint i, a, b; + for (i = 0; i < n; i++) { + b = (GLuint) p[i]; /* words are often faster than bytes */ + a = ((b & 0x01) << 7) | + ((b & 0x02) << 5) | + ((b & 0x04) << 3) | + ((b & 0x08) << 1) | + ((b & 0x10) >> 1) | + ((b & 0x20) >> 3) | + ((b & 0x40) >> 5) | + ((b & 0x80) >> 7); + p[i] = (GLubyte) a; + } +} + + + +/* + * Unpack a 32x32 pixel polygon stipple from user memory using the + * current pixel unpack settings. + */ +void +_mesa_unpack_polygon_stipple( const GLubyte *pattern, GLuint dest[32], + const struct gl_pixelstore_attrib *unpacking ) +{ + GLubyte *ptrn = (GLubyte *) _mesa_unpack_bitmap(32, 32, pattern, unpacking); + if (ptrn) { + /* Convert pattern from GLubytes to GLuints and handle big/little + * endian differences + */ + GLubyte *p = ptrn; + GLint i; + for (i = 0; i < 32; i++) { + dest[i] = (p[0] << 24) + | (p[1] << 16) + | (p[2] << 8) + | (p[3] ); + p += 4; + } + free(ptrn); + } +} + + +/* + * Pack polygon stipple into user memory given current pixel packing + * settings. + */ +void +_mesa_pack_polygon_stipple( const GLuint pattern[32], GLubyte *dest, + const struct gl_pixelstore_attrib *packing ) +{ + /* Convert pattern from GLuints to GLubytes to handle big/little + * endian differences. + */ + GLubyte ptrn[32*4]; + GLint i; + for (i = 0; i < 32; i++) { + ptrn[i * 4 + 0] = (GLubyte) ((pattern[i] >> 24) & 0xff); + ptrn[i * 4 + 1] = (GLubyte) ((pattern[i] >> 16) & 0xff); + ptrn[i * 4 + 2] = (GLubyte) ((pattern[i] >> 8 ) & 0xff); + ptrn[i * 4 + 3] = (GLubyte) ((pattern[i] ) & 0xff); + } + + _mesa_pack_bitmap(32, 32, ptrn, dest, packing); +} + + +/* + * Unpack bitmap data. Resulting data will be in most-significant-bit-first + * order with row alignment = 1 byte. + */ +GLvoid * +_mesa_unpack_bitmap( GLint width, GLint height, const GLubyte *pixels, + const struct gl_pixelstore_attrib *packing ) +{ + GLint bytes, row, width_in_bytes; + GLubyte *buffer, *dst; + + if (!pixels) + return NULL; + + /* Alloc dest storage */ + bytes = ((width + 7) / 8 * height); + buffer = (GLubyte *) malloc( bytes ); + if (!buffer) + return NULL; + + width_in_bytes = CEILING( width, 8 ); + dst = buffer; + for (row = 0; row < height; row++) { + const GLubyte *src = (const GLubyte *) + _mesa_image_address2d(packing, pixels, width, height, + GL_COLOR_INDEX, GL_BITMAP, row, 0); + if (!src) { + free(buffer); + return NULL; + } + + if ((packing->SkipPixels & 7) == 0) { + memcpy( dst, src, width_in_bytes ); + if (packing->LsbFirst) { + flip_bytes( dst, width_in_bytes ); + } + } + else { + /* handling SkipPixels is a bit tricky (no pun intended!) */ + GLint i; + if (packing->LsbFirst) { + GLubyte srcMask = 1 << (packing->SkipPixels & 0x7); + GLubyte dstMask = 128; + const GLubyte *s = src; + GLubyte *d = dst; + *d = 0; + for (i = 0; i < width; i++) { + if (*s & srcMask) { + *d |= dstMask; + } + if (srcMask == 128) { + srcMask = 1; + s++; + } + else { + srcMask = srcMask << 1; + } + if (dstMask == 1) { + dstMask = 128; + d++; + *d = 0; + } + else { + dstMask = dstMask >> 1; + } + } + } + else { + GLubyte srcMask = 128 >> (packing->SkipPixels & 0x7); + GLubyte dstMask = 128; + const GLubyte *s = src; + GLubyte *d = dst; + *d = 0; + for (i = 0; i < width; i++) { + if (*s & srcMask) { + *d |= dstMask; + } + if (srcMask == 1) { + srcMask = 128; + s++; + } + else { + srcMask = srcMask >> 1; + } + if (dstMask == 1) { + dstMask = 128; + d++; + *d = 0; + } + else { + dstMask = dstMask >> 1; + } + } + } + } + dst += width_in_bytes; + } + + return buffer; +} + + +/* + * Pack bitmap data. + */ +void +_mesa_pack_bitmap( GLint width, GLint height, const GLubyte *source, + GLubyte *dest, const struct gl_pixelstore_attrib *packing ) +{ + GLint row, width_in_bytes; + const GLubyte *src; + + if (!source) + return; + + width_in_bytes = CEILING( width, 8 ); + src = source; + for (row = 0; row < height; row++) { + GLubyte *dst = (GLubyte *) _mesa_image_address2d(packing, dest, + width, height, GL_COLOR_INDEX, GL_BITMAP, row, 0); + if (!dst) + return; + + if ((packing->SkipPixels & 7) == 0) { + memcpy( dst, src, width_in_bytes ); + if (packing->LsbFirst) { + flip_bytes( dst, width_in_bytes ); + } + } + else { + /* handling SkipPixels is a bit tricky (no pun intended!) */ + GLint i; + if (packing->LsbFirst) { + GLubyte srcMask = 128; + GLubyte dstMask = 1 << (packing->SkipPixels & 0x7); + const GLubyte *s = src; + GLubyte *d = dst; + *d = 0; + for (i = 0; i < width; i++) { + if (*s & srcMask) { + *d |= dstMask; + } + if (srcMask == 1) { + srcMask = 128; + s++; + } + else { + srcMask = srcMask >> 1; + } + if (dstMask == 128) { + dstMask = 1; + d++; + *d = 0; + } + else { + dstMask = dstMask << 1; + } + } + } + else { + GLubyte srcMask = 128; + GLubyte dstMask = 128 >> (packing->SkipPixels & 0x7); + const GLubyte *s = src; + GLubyte *d = dst; + *d = 0; + for (i = 0; i < width; i++) { + if (*s & srcMask) { + *d |= dstMask; + } + if (srcMask == 1) { + srcMask = 128; + s++; + } + else { + srcMask = srcMask >> 1; + } + if (dstMask == 1) { + dstMask = 128; + d++; + *d = 0; + } + else { + dstMask = dstMask >> 1; + } + } + } + } + src += width_in_bytes; + } +} + + +/** + * Get indexes of color components for a basic color format, such as + * GL_RGBA, GL_RED, GL_LUMINANCE_ALPHA, etc. Return -1 for indexes + * that do not apply. + */ +static void +get_component_indexes(GLenum format, + GLint *redIndex, + GLint *greenIndex, + GLint *blueIndex, + GLint *alphaIndex, + GLint *luminanceIndex, + GLint *intensityIndex) +{ + *redIndex = -1; + *greenIndex = -1; + *blueIndex = -1; + *alphaIndex = -1; + *luminanceIndex = -1; + *intensityIndex = -1; + + switch (format) { + case GL_LUMINANCE: + case GL_LUMINANCE_INTEGER_EXT: + *luminanceIndex = 0; + break; + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE_ALPHA_INTEGER_EXT: + *luminanceIndex = 0; + *alphaIndex = 1; + break; + case GL_INTENSITY: + *intensityIndex = 0; + break; + case GL_RED: + case GL_RED_INTEGER_EXT: + *redIndex = 0; + break; + case GL_GREEN: + case GL_GREEN_INTEGER_EXT: + *greenIndex = 0; + break; + case GL_BLUE: + case GL_BLUE_INTEGER_EXT: + *blueIndex = 0; + break; + case GL_ALPHA: + case GL_ALPHA_INTEGER_EXT: + *alphaIndex = 0; + break; + case GL_RG: + case GL_RG_INTEGER: + *redIndex = 0; + *greenIndex = 1; + break; + case GL_RGB: + case GL_RGB_INTEGER_EXT: + *redIndex = 0; + *greenIndex = 1; + *blueIndex = 2; + break; + case GL_BGR: + case GL_BGR_INTEGER_EXT: + *blueIndex = 0; + *greenIndex = 1; + *redIndex = 2; + break; + case GL_RGBA: + case GL_RGBA_INTEGER_EXT: + *redIndex = 0; + *greenIndex = 1; + *blueIndex = 2; + *alphaIndex = 3; + break; + case GL_BGRA: + case GL_BGRA_INTEGER: + *redIndex = 2; + *greenIndex = 1; + *blueIndex = 0; + *alphaIndex = 3; + break; + case GL_ABGR_EXT: + *redIndex = 3; + *greenIndex = 2; + *blueIndex = 1; + *alphaIndex = 0; + break; + case GL_DU8DV8_ATI: + case GL_DUDV_ATI: + *redIndex = 0; + *greenIndex = 1; + break; + default: + assert(0 && "bad format in get_component_indexes()"); + } +} + + + +/** + * For small integer types, return the min and max possible values. + * Used for clamping floats to unscaled integer types. + * \return GL_TRUE if type is handled, GL_FALSE otherwise. + */ +static GLboolean +get_type_min_max(GLenum type, GLfloat *min, GLfloat *max) +{ + switch (type) { + case GL_BYTE: + *min = -128.0; + *max = 127.0; + return GL_TRUE; + case GL_UNSIGNED_BYTE: + *min = 0.0; + *max = 255.0; + return GL_TRUE; + case GL_SHORT: + *min = -32768.0; + *max = 32767.0; + return GL_TRUE; + case GL_UNSIGNED_SHORT: + *min = 0.0; + *max = 65535.0; + return GL_TRUE; + default: + return GL_FALSE; + } +} + + + +/** + * Used to pack an array [][4] of RGBA float colors as specified + * by the dstFormat, dstType and dstPacking. Used by glReadPixels. + * Historically, the RGBA values were in [0,1] and rescaled to fit + * into GLubytes, etc. But with new integer formats, the RGBA values + * may have any value and we don't always rescale when converting to + * integers. + * + * Note: the rgba values will be modified by this function when any pixel + * transfer ops are enabled. + */ +void +_mesa_pack_rgba_span_float(struct gl_context *ctx, GLuint n, GLfloat rgba[][4], + GLenum dstFormat, GLenum dstType, + GLvoid *dstAddr, + const struct gl_pixelstore_attrib *dstPacking, + GLbitfield transferOps) +{ + GLfloat *luminance; + const GLint comps = _mesa_components_in_format(dstFormat); + const GLboolean intDstFormat = _mesa_is_integer_format(dstFormat); + GLuint i; + + if (dstFormat == GL_LUMINANCE || + dstFormat == GL_LUMINANCE_ALPHA || + dstFormat == GL_LUMINANCE_INTEGER_EXT || + dstFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT) { + luminance = (GLfloat *) malloc(n * sizeof(GLfloat)); + if (!luminance) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel packing"); + return; + } + } + else { + luminance = NULL; + } + + if (transferOps) { + _mesa_apply_rgba_transfer_ops(ctx, transferOps, n, rgba); + } + + /* + * Component clamping (besides clamping to [0,1] in + * _mesa_apply_rgba_transfer_ops()). + */ + if (intDstFormat) { + /* clamping to dest type's min/max values */ + GLfloat min, max; + if (get_type_min_max(dstType, &min, &max)) { + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = CLAMP(rgba[i][RCOMP], min, max); + rgba[i][GCOMP] = CLAMP(rgba[i][GCOMP], min, max); + rgba[i][BCOMP] = CLAMP(rgba[i][BCOMP], min, max); + rgba[i][ACOMP] = CLAMP(rgba[i][ACOMP], min, max); + } + } + } + else if (dstFormat == GL_LUMINANCE || dstFormat == GL_LUMINANCE_ALPHA) { + /* compute luminance values */ + if (transferOps & IMAGE_CLAMP_BIT) { + for (i = 0; i < n; i++) { + GLfloat sum = rgba[i][RCOMP] + rgba[i][GCOMP] + rgba[i][BCOMP]; + luminance[i] = CLAMP(sum, 0.0F, 1.0F); + } + } + else { + for (i = 0; i < n; i++) { + luminance[i] = rgba[i][RCOMP] + rgba[i][GCOMP] + rgba[i][BCOMP]; + } + } + } + + /* + * Pack/store the pixels. Ugh! Lots of cases!!! + */ + switch (dstType) { + case GL_UNSIGNED_BYTE: + { + GLubyte *dst = (GLubyte *) dstAddr; + switch (dstFormat) { + case GL_RED: + for (i=0;iSwapBytes) { + GLint swapSize = _mesa_sizeof_packed_type(dstType); + if (swapSize == 2) { + if (dstPacking->SwapBytes) { + _mesa_swap2((GLushort *) dstAddr, n * comps); + } + } + else if (swapSize == 4) { + if (dstPacking->SwapBytes) { + _mesa_swap4((GLuint *) dstAddr, n * comps); + } + } + } + + free(luminance); +} + + + +#define SWAP2BYTE(VALUE) \ + { \ + GLubyte *bytes = (GLubyte *) &(VALUE); \ + GLubyte tmp = bytes[0]; \ + bytes[0] = bytes[1]; \ + bytes[1] = tmp; \ + } + +#define SWAP4BYTE(VALUE) \ + { \ + GLubyte *bytes = (GLubyte *) &(VALUE); \ + GLubyte tmp = bytes[0]; \ + bytes[0] = bytes[3]; \ + bytes[3] = tmp; \ + tmp = bytes[1]; \ + bytes[1] = bytes[2]; \ + bytes[2] = tmp; \ + } + + +static void +extract_uint_indexes(GLuint n, GLuint indexes[], + GLenum srcFormat, GLenum srcType, const GLvoid *src, + const struct gl_pixelstore_attrib *unpack ) +{ + ASSERT(srcFormat == GL_COLOR_INDEX || srcFormat == GL_STENCIL_INDEX); + + ASSERT(srcType == GL_BITMAP || + srcType == GL_UNSIGNED_BYTE || + srcType == GL_BYTE || + srcType == GL_UNSIGNED_SHORT || + srcType == GL_SHORT || + srcType == GL_UNSIGNED_INT || + srcType == GL_INT || + srcType == GL_UNSIGNED_INT_24_8_EXT || + srcType == GL_HALF_FLOAT_ARB || + srcType == GL_FLOAT); + + switch (srcType) { + case GL_BITMAP: + { + GLubyte *ubsrc = (GLubyte *) src; + if (unpack->LsbFirst) { + GLubyte mask = 1 << (unpack->SkipPixels & 0x7); + GLuint i; + for (i = 0; i < n; i++) { + indexes[i] = (*ubsrc & mask) ? 1 : 0; + if (mask == 128) { + mask = 1; + ubsrc++; + } + else { + mask = mask << 1; + } + } + } + else { + GLubyte mask = 128 >> (unpack->SkipPixels & 0x7); + GLuint i; + for (i = 0; i < n; i++) { + indexes[i] = (*ubsrc & mask) ? 1 : 0; + if (mask == 1) { + mask = 128; + ubsrc++; + } + else { + mask = mask >> 1; + } + } + } + } + break; + case GL_UNSIGNED_BYTE: + { + GLuint i; + const GLubyte *s = (const GLubyte *) src; + for (i = 0; i < n; i++) + indexes[i] = s[i]; + } + break; + case GL_BYTE: + { + GLuint i; + const GLbyte *s = (const GLbyte *) src; + for (i = 0; i < n; i++) + indexes[i] = s[i]; + } + break; + case GL_UNSIGNED_SHORT: + { + GLuint i; + const GLushort *s = (const GLushort *) src; + if (unpack->SwapBytes) { + for (i = 0; i < n; i++) { + GLushort value = s[i]; + SWAP2BYTE(value); + indexes[i] = value; + } + } + else { + for (i = 0; i < n; i++) + indexes[i] = s[i]; + } + } + break; + case GL_SHORT: + { + GLuint i; + const GLshort *s = (const GLshort *) src; + if (unpack->SwapBytes) { + for (i = 0; i < n; i++) { + GLshort value = s[i]; + SWAP2BYTE(value); + indexes[i] = value; + } + } + else { + for (i = 0; i < n; i++) + indexes[i] = s[i]; + } + } + break; + case GL_UNSIGNED_INT: + { + GLuint i; + const GLuint *s = (const GLuint *) src; + if (unpack->SwapBytes) { + for (i = 0; i < n; i++) { + GLuint value = s[i]; + SWAP4BYTE(value); + indexes[i] = value; + } + } + else { + for (i = 0; i < n; i++) + indexes[i] = s[i]; + } + } + break; + case GL_INT: + { + GLuint i; + const GLint *s = (const GLint *) src; + if (unpack->SwapBytes) { + for (i = 0; i < n; i++) { + GLint value = s[i]; + SWAP4BYTE(value); + indexes[i] = value; + } + } + else { + for (i = 0; i < n; i++) + indexes[i] = s[i]; + } + } + break; + case GL_FLOAT: + { + GLuint i; + const GLfloat *s = (const GLfloat *) src; + if (unpack->SwapBytes) { + for (i = 0; i < n; i++) { + GLfloat value = s[i]; + SWAP4BYTE(value); + indexes[i] = (GLuint) value; + } + } + else { + for (i = 0; i < n; i++) + indexes[i] = (GLuint) s[i]; + } + } + break; + case GL_HALF_FLOAT_ARB: + { + GLuint i; + const GLhalfARB *s = (const GLhalfARB *) src; + if (unpack->SwapBytes) { + for (i = 0; i < n; i++) { + GLhalfARB value = s[i]; + SWAP2BYTE(value); + indexes[i] = (GLuint) _mesa_half_to_float(value); + } + } + else { + for (i = 0; i < n; i++) + indexes[i] = (GLuint) _mesa_half_to_float(s[i]); + } + } + break; + case GL_UNSIGNED_INT_24_8_EXT: + { + GLuint i; + const GLuint *s = (const GLuint *) src; + if (unpack->SwapBytes) { + for (i = 0; i < n; i++) { + GLuint value = s[i]; + SWAP4BYTE(value); + indexes[i] = value & 0xff; /* lower 8 bits */ + } + } + else { + for (i = 0; i < n; i++) + indexes[i] = s[i] & 0xff; /* lower 8 bits */ + } + } + break; + + default: + _mesa_problem(NULL, "bad srcType in extract_uint_indexes"); + return; + } +} + + +/** + * Return source/dest RGBA indexes for unpacking pixels. + */ +static void +get_component_mapping(GLenum format, + GLint *rSrc, + GLint *gSrc, + GLint *bSrc, + GLint *aSrc, + GLint *rDst, + GLint *gDst, + GLint *bDst, + GLint *aDst) +{ + switch (format) { + case GL_RED: + case GL_RED_INTEGER_EXT: + *rSrc = 0; + *gSrc = *bSrc = *aSrc = -1; + break; + case GL_GREEN: + case GL_GREEN_INTEGER_EXT: + *gSrc = 0; + *rSrc = *bSrc = *aSrc = -1; + break; + case GL_BLUE: + case GL_BLUE_INTEGER_EXT: + *bSrc = 0; + *rSrc = *gSrc = *aSrc = -1; + break; + case GL_ALPHA: + case GL_ALPHA_INTEGER_EXT: + *rSrc = *gSrc = *bSrc = -1; + *aSrc = 0; + break; + case GL_LUMINANCE: + case GL_LUMINANCE_INTEGER_EXT: + *rSrc = *gSrc = *bSrc = 0; + *aSrc = -1; + break; + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE_ALPHA_INTEGER_EXT: + *rSrc = *gSrc = *bSrc = 0; + *aSrc = 1; + break; + case GL_INTENSITY: + *rSrc = *gSrc = *bSrc = *aSrc = 0; + break; + case GL_RG: + case GL_RG_INTEGER: + *rSrc = 0; + *gSrc = 1; + *bSrc = -1; + *aSrc = -1; + *rDst = 0; + *gDst = 1; + *bDst = 2; + *aDst = 3; + break; + case GL_RGB: + case GL_RGB_INTEGER: + *rSrc = 0; + *gSrc = 1; + *bSrc = 2; + *aSrc = -1; + *rDst = 0; + *gDst = 1; + *bDst = 2; + *aDst = 3; + break; + case GL_BGR: + *rSrc = 2; + *gSrc = 1; + *bSrc = 0; + *aSrc = -1; + *rDst = 2; + *gDst = 1; + *bDst = 0; + *aDst = 3; + break; + case GL_RGBA: + case GL_RGBA_INTEGER: + *rSrc = 0; + *gSrc = 1; + *bSrc = 2; + *aSrc = 3; + *rDst = 0; + *gDst = 1; + *bDst = 2; + *aDst = 3; + break; + case GL_BGRA: + *rSrc = 2; + *gSrc = 1; + *bSrc = 0; + *aSrc = 3; + *rDst = 2; + *gDst = 1; + *bDst = 0; + *aDst = 3; + break; + case GL_ABGR_EXT: + *rSrc = 3; + *gSrc = 2; + *bSrc = 1; + *aSrc = 0; + *rDst = 3; + *gDst = 2; + *bDst = 1; + *aDst = 0; + break; + case GL_DU8DV8_ATI: + case GL_DUDV_ATI: + *rSrc = 0; + *gSrc = 1; + *bSrc = -1; + *aSrc = -1; + break; + default: + _mesa_problem(NULL, "bad srcFormat %s in get_component_mapping", + _mesa_lookup_enum_by_nr(format)); + return; + } +} + + + +/* + * This function extracts floating point RGBA values from arbitrary + * image data. srcFormat and srcType are the format and type parameters + * passed to glDrawPixels, glTexImage[123]D, glTexSubImage[123]D, etc. + * + * Refering to section 3.6.4 of the OpenGL 1.2 spec, this function + * implements the "Conversion to floating point", "Conversion to RGB", + * and "Final Expansion to RGBA" operations. + * + * Args: n - number of pixels + * rgba - output colors + * srcFormat - format of incoming data + * srcType - data type of incoming data + * src - source data pointer + * swapBytes - perform byteswapping of incoming data? + */ +static void +extract_float_rgba(GLuint n, GLfloat rgba[][4], + GLenum srcFormat, GLenum srcType, const GLvoid *src, + GLboolean swapBytes) +{ + GLint rSrc, gSrc, bSrc, aSrc; + GLint stride; + GLint rDst, bDst, gDst, aDst; + GLboolean intFormat; + GLfloat rs = 1.0f, gs = 1.0f, bs = 1.0f, as = 1.0f; /* scale factors */ + + ASSERT(srcFormat == GL_RED || + srcFormat == GL_GREEN || + srcFormat == GL_BLUE || + srcFormat == GL_ALPHA || + srcFormat == GL_LUMINANCE || + srcFormat == GL_LUMINANCE_ALPHA || + srcFormat == GL_INTENSITY || + srcFormat == GL_RG || + srcFormat == GL_RGB || + srcFormat == GL_BGR || + srcFormat == GL_RGBA || + srcFormat == GL_BGRA || + srcFormat == GL_ABGR_EXT || + srcFormat == GL_DU8DV8_ATI || + srcFormat == GL_DUDV_ATI || + srcFormat == GL_RED_INTEGER_EXT || + srcFormat == GL_GREEN_INTEGER_EXT || + srcFormat == GL_BLUE_INTEGER_EXT || + srcFormat == GL_ALPHA_INTEGER_EXT || + srcFormat == GL_RGB_INTEGER_EXT || + srcFormat == GL_RGBA_INTEGER_EXT || + srcFormat == GL_BGR_INTEGER_EXT || + srcFormat == GL_BGRA_INTEGER_EXT || + srcFormat == GL_LUMINANCE_INTEGER_EXT || + srcFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT); + + ASSERT(srcType == GL_UNSIGNED_BYTE || + srcType == GL_BYTE || + srcType == GL_UNSIGNED_SHORT || + srcType == GL_SHORT || + srcType == GL_UNSIGNED_INT || + srcType == GL_INT || + srcType == GL_HALF_FLOAT_ARB || + srcType == GL_FLOAT || + srcType == GL_UNSIGNED_BYTE_3_3_2 || + srcType == GL_UNSIGNED_BYTE_2_3_3_REV || + srcType == GL_UNSIGNED_SHORT_5_6_5 || + srcType == GL_UNSIGNED_SHORT_5_6_5_REV || + srcType == GL_UNSIGNED_SHORT_4_4_4_4 || + srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV || + srcType == GL_UNSIGNED_SHORT_5_5_5_1 || + srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV || + srcType == GL_UNSIGNED_INT_8_8_8_8 || + srcType == GL_UNSIGNED_INT_8_8_8_8_REV || + srcType == GL_UNSIGNED_INT_10_10_10_2 || + srcType == GL_UNSIGNED_INT_2_10_10_10_REV || + srcType == GL_UNSIGNED_INT_5_9_9_9_REV || + srcType == GL_UNSIGNED_INT_10F_11F_11F_REV); + + get_component_mapping(srcFormat, + &rSrc, &gSrc, &bSrc, &aSrc, + &rDst, &gDst, &bDst, &aDst); + + stride = _mesa_components_in_format(srcFormat); + + intFormat = _mesa_is_integer_format(srcFormat); + +#define PROCESS(SRC_INDEX, DST_INDEX, DEFAULT_FLT, DEFAULT_INT, TYPE, CONVERSION) \ + if ((SRC_INDEX) < 0) { \ + GLuint i; \ + if (intFormat) { \ + for (i = 0; i < n; i++) { \ + rgba[i][DST_INDEX] = DEFAULT_INT; \ + } \ + } \ + else { \ + for (i = 0; i < n; i++) { \ + rgba[i][DST_INDEX] = DEFAULT_FLT; \ + } \ + } \ + } \ + else if (swapBytes) { \ + const TYPE *s = (const TYPE *) src; \ + GLuint i; \ + for (i = 0; i < n; i++) { \ + TYPE value = s[SRC_INDEX]; \ + if (sizeof(TYPE) == 2) { \ + SWAP2BYTE(value); \ + } \ + else if (sizeof(TYPE) == 4) { \ + SWAP4BYTE(value); \ + } \ + if (intFormat) \ + rgba[i][DST_INDEX] = (GLfloat) value; \ + else \ + rgba[i][DST_INDEX] = (GLfloat) CONVERSION(value); \ + s += stride; \ + } \ + } \ + else { \ + const TYPE *s = (const TYPE *) src; \ + GLuint i; \ + if (intFormat) { \ + for (i = 0; i < n; i++) { \ + rgba[i][DST_INDEX] = (GLfloat) s[SRC_INDEX]; \ + s += stride; \ + } \ + } \ + else { \ + for (i = 0; i < n; i++) { \ + rgba[i][DST_INDEX] = (GLfloat) CONVERSION(s[SRC_INDEX]); \ + s += stride; \ + } \ + } \ + } + + switch (srcType) { + case GL_UNSIGNED_BYTE: + PROCESS(rSrc, RCOMP, 0.0F, 0, GLubyte, UBYTE_TO_FLOAT); + PROCESS(gSrc, GCOMP, 0.0F, 0, GLubyte, UBYTE_TO_FLOAT); + PROCESS(bSrc, BCOMP, 0.0F, 0, GLubyte, UBYTE_TO_FLOAT); + PROCESS(aSrc, ACOMP, 1.0F, 255, GLubyte, UBYTE_TO_FLOAT); + break; + case GL_BYTE: + PROCESS(rSrc, RCOMP, 0.0F, 0, GLbyte, BYTE_TO_FLOAT); + PROCESS(gSrc, GCOMP, 0.0F, 0, GLbyte, BYTE_TO_FLOAT); + PROCESS(bSrc, BCOMP, 0.0F, 0, GLbyte, BYTE_TO_FLOAT); + PROCESS(aSrc, ACOMP, 1.0F, 127, GLbyte, BYTE_TO_FLOAT); + break; + case GL_UNSIGNED_SHORT: + PROCESS(rSrc, RCOMP, 0.0F, 0, GLushort, USHORT_TO_FLOAT); + PROCESS(gSrc, GCOMP, 0.0F, 0, GLushort, USHORT_TO_FLOAT); + PROCESS(bSrc, BCOMP, 0.0F, 0, GLushort, USHORT_TO_FLOAT); + PROCESS(aSrc, ACOMP, 1.0F, 0xffff, GLushort, USHORT_TO_FLOAT); + break; + case GL_SHORT: + PROCESS(rSrc, RCOMP, 0.0F, 0, GLshort, SHORT_TO_FLOAT); + PROCESS(gSrc, GCOMP, 0.0F, 0, GLshort, SHORT_TO_FLOAT); + PROCESS(bSrc, BCOMP, 0.0F, 0, GLshort, SHORT_TO_FLOAT); + PROCESS(aSrc, ACOMP, 1.0F, 32767, GLshort, SHORT_TO_FLOAT); + break; + case GL_UNSIGNED_INT: + PROCESS(rSrc, RCOMP, 0.0F, 0, GLuint, UINT_TO_FLOAT); + PROCESS(gSrc, GCOMP, 0.0F, 0, GLuint, UINT_TO_FLOAT); + PROCESS(bSrc, BCOMP, 0.0F, 0, GLuint, UINT_TO_FLOAT); + PROCESS(aSrc, ACOMP, 1.0F, 0xffffffff, GLuint, UINT_TO_FLOAT); + break; + case GL_INT: + PROCESS(rSrc, RCOMP, 0.0F, 0, GLint, INT_TO_FLOAT); + PROCESS(gSrc, GCOMP, 0.0F, 0, GLint, INT_TO_FLOAT); + PROCESS(bSrc, BCOMP, 0.0F, 0, GLint, INT_TO_FLOAT); + PROCESS(aSrc, ACOMP, 1.0F, 2147483647, GLint, INT_TO_FLOAT); + break; + case GL_FLOAT: + PROCESS(rSrc, RCOMP, 0.0F, 0.0F, GLfloat, (GLfloat)); + PROCESS(gSrc, GCOMP, 0.0F, 0.0F, GLfloat, (GLfloat)); + PROCESS(bSrc, BCOMP, 0.0F, 0.0F, GLfloat, (GLfloat)); + PROCESS(aSrc, ACOMP, 1.0F, 1.0F, GLfloat, (GLfloat)); + break; + case GL_HALF_FLOAT_ARB: + PROCESS(rSrc, RCOMP, 0.0F, 0.0F, GLhalfARB, _mesa_half_to_float); + PROCESS(gSrc, GCOMP, 0.0F, 0.0F, GLhalfARB, _mesa_half_to_float); + PROCESS(bSrc, BCOMP, 0.0F, 0.0F, GLhalfARB, _mesa_half_to_float); + PROCESS(aSrc, ACOMP, 1.0F, 1.0F, GLhalfARB, _mesa_half_to_float); + break; + case GL_UNSIGNED_BYTE_3_3_2: + { + const GLubyte *ubsrc = (const GLubyte *) src; + GLuint i; + if (!intFormat) { + rs = 1.0F / 7.0F; + gs = 1.0F / 7.0F; + bs = 1.0F / 3.0F; + } + for (i = 0; i < n; i ++) { + GLubyte p = ubsrc[i]; + rgba[i][rDst] = ((p >> 5) ) * rs; + rgba[i][gDst] = ((p >> 2) & 0x7) * gs; + rgba[i][bDst] = ((p ) & 0x3) * bs; + rgba[i][aDst] = 1.0F; + } + } + break; + case GL_UNSIGNED_BYTE_2_3_3_REV: + { + const GLubyte *ubsrc = (const GLubyte *) src; + GLuint i; + if (!intFormat) { + rs = 1.0F / 7.0F; + gs = 1.0F / 7.0F; + bs = 1.0F / 3.0F; + } + for (i = 0; i < n; i ++) { + GLubyte p = ubsrc[i]; + rgba[i][rDst] = ((p ) & 0x7) * rs; + rgba[i][gDst] = ((p >> 3) & 0x7) * gs; + rgba[i][bDst] = ((p >> 6) ) * bs; + rgba[i][aDst] = 1.0F; + } + } + break; + case GL_UNSIGNED_SHORT_5_6_5: + if (!intFormat) { + rs = 1.0F / 31.0F; + gs = 1.0F / 63.0F; + bs = 1.0F / 31.0F; + } + if (swapBytes) { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + SWAP2BYTE(p); + rgba[i][rDst] = ((p >> 11) ) * rs; + rgba[i][gDst] = ((p >> 5) & 0x3f) * gs; + rgba[i][bDst] = ((p ) & 0x1f) * bs; + rgba[i][aDst] = 1.0F; + } + } + else { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + rgba[i][rDst] = ((p >> 11) ) * rs; + rgba[i][gDst] = ((p >> 5) & 0x3f) * gs; + rgba[i][bDst] = ((p ) & 0x1f) * bs; + rgba[i][aDst] = 1.0F; + } + } + break; + case GL_UNSIGNED_SHORT_5_6_5_REV: + if (!intFormat) { + rs = 1.0F / 31.0F; + gs = 1.0F / 63.0F; + bs = 1.0F / 31.0F; + } + if (swapBytes) { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + SWAP2BYTE(p); + rgba[i][rDst] = ((p ) & 0x1f) * rs; + rgba[i][gDst] = ((p >> 5) & 0x3f) * gs; + rgba[i][bDst] = ((p >> 11) ) * bs; + rgba[i][aDst] = 1.0F; + } + } + else { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + rgba[i][rDst] = ((p ) & 0x1f) * rs; + rgba[i][gDst] = ((p >> 5) & 0x3f) * gs; + rgba[i][bDst] = ((p >> 11) ) * bs; + rgba[i][aDst] = 1.0F; + } + } + break; + case GL_UNSIGNED_SHORT_4_4_4_4: + if (!intFormat) { + rs = gs = bs = as = 1.0F / 15.0F; + } + if (swapBytes) { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + SWAP2BYTE(p); + rgba[i][rDst] = ((p >> 12) ) * rs; + rgba[i][gDst] = ((p >> 8) & 0xf) * gs; + rgba[i][bDst] = ((p >> 4) & 0xf) * bs; + rgba[i][aDst] = ((p ) & 0xf) * as; + } + } + else { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + rgba[i][rDst] = ((p >> 12) ) * rs; + rgba[i][gDst] = ((p >> 8) & 0xf) * gs; + rgba[i][bDst] = ((p >> 4) & 0xf) * bs; + rgba[i][aDst] = ((p ) & 0xf) * as; + } + } + break; + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + if (!intFormat) { + rs = gs = bs = as = 1.0F / 15.0F; + } + if (swapBytes) { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + SWAP2BYTE(p); + rgba[i][rDst] = ((p ) & 0xf) * rs; + rgba[i][gDst] = ((p >> 4) & 0xf) * gs; + rgba[i][bDst] = ((p >> 8) & 0xf) * bs; + rgba[i][aDst] = ((p >> 12) ) * as; + } + } + else { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + rgba[i][rDst] = ((p ) & 0xf) * rs; + rgba[i][gDst] = ((p >> 4) & 0xf) * gs; + rgba[i][bDst] = ((p >> 8) & 0xf) * bs; + rgba[i][aDst] = ((p >> 12) ) * as; + } + } + break; + case GL_UNSIGNED_SHORT_5_5_5_1: + if (!intFormat) { + rs = gs = bs = 1.0F / 31.0F; + } + if (swapBytes) { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + SWAP2BYTE(p); + rgba[i][rDst] = ((p >> 11) ) * rs; + rgba[i][gDst] = ((p >> 6) & 0x1f) * gs; + rgba[i][bDst] = ((p >> 1) & 0x1f) * bs; + rgba[i][aDst] = ((p ) & 0x1) * as; + } + } + else { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + rgba[i][rDst] = ((p >> 11) ) * rs; + rgba[i][gDst] = ((p >> 6) & 0x1f) * gs; + rgba[i][bDst] = ((p >> 1) & 0x1f) * bs; + rgba[i][aDst] = ((p ) & 0x1) * as; + } + } + break; + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + if (!intFormat) { + rs = gs = bs = 1.0F / 31.0F; + } + if (swapBytes) { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + SWAP2BYTE(p); + rgba[i][rDst] = ((p ) & 0x1f) * rs; + rgba[i][gDst] = ((p >> 5) & 0x1f) * gs; + rgba[i][bDst] = ((p >> 10) & 0x1f) * bs; + rgba[i][aDst] = ((p >> 15) ) * as; + } + } + else { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + rgba[i][rDst] = ((p ) & 0x1f) * rs; + rgba[i][gDst] = ((p >> 5) & 0x1f) * gs; + rgba[i][bDst] = ((p >> 10) & 0x1f) * bs; + rgba[i][aDst] = ((p >> 15) ) * as; + } + } + break; + case GL_UNSIGNED_INT_8_8_8_8: + if (swapBytes) { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + if (intFormat) { + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + rgba[i][rDst] = (GLfloat) ((p ) & 0xff); + rgba[i][gDst] = (GLfloat) ((p >> 8) & 0xff); + rgba[i][bDst] = (GLfloat) ((p >> 16) & 0xff); + rgba[i][aDst] = (GLfloat) ((p >> 24) ); + } + } + else { + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + rgba[i][rDst] = UBYTE_TO_FLOAT((p ) & 0xff); + rgba[i][gDst] = UBYTE_TO_FLOAT((p >> 8) & 0xff); + rgba[i][bDst] = UBYTE_TO_FLOAT((p >> 16) & 0xff); + rgba[i][aDst] = UBYTE_TO_FLOAT((p >> 24) ); + } + } + } + else { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + if (intFormat) { + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + rgba[i][rDst] = (GLfloat) ((p >> 24) ); + rgba[i][gDst] = (GLfloat) ((p >> 16) & 0xff); + rgba[i][bDst] = (GLfloat) ((p >> 8) & 0xff); + rgba[i][aDst] = (GLfloat) ((p ) & 0xff); + } + } + else { + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + rgba[i][rDst] = UBYTE_TO_FLOAT((p >> 24) ); + rgba[i][gDst] = UBYTE_TO_FLOAT((p >> 16) & 0xff); + rgba[i][bDst] = UBYTE_TO_FLOAT((p >> 8) & 0xff); + rgba[i][aDst] = UBYTE_TO_FLOAT((p ) & 0xff); + } + } + } + break; + case GL_UNSIGNED_INT_8_8_8_8_REV: + if (swapBytes) { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + if (intFormat) { + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + rgba[i][rDst] = (GLfloat) ((p >> 24) ); + rgba[i][gDst] = (GLfloat) ((p >> 16) & 0xff); + rgba[i][bDst] = (GLfloat) ((p >> 8) & 0xff); + rgba[i][aDst] = (GLfloat) ((p ) & 0xff); + } + } + else { + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + rgba[i][rDst] = UBYTE_TO_FLOAT((p >> 24) ); + rgba[i][gDst] = UBYTE_TO_FLOAT((p >> 16) & 0xff); + rgba[i][bDst] = UBYTE_TO_FLOAT((p >> 8) & 0xff); + rgba[i][aDst] = UBYTE_TO_FLOAT((p ) & 0xff); + } + } + } + else { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + if (intFormat) { + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + rgba[i][rDst] = (GLfloat) ((p ) & 0xff); + rgba[i][gDst] = (GLfloat) ((p >> 8) & 0xff); + rgba[i][bDst] = (GLfloat) ((p >> 16) & 0xff); + rgba[i][aDst] = (GLfloat) ((p >> 24) ); + } + } + else { + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + rgba[i][rDst] = UBYTE_TO_FLOAT((p ) & 0xff); + rgba[i][gDst] = UBYTE_TO_FLOAT((p >> 8) & 0xff); + rgba[i][bDst] = UBYTE_TO_FLOAT((p >> 16) & 0xff); + rgba[i][aDst] = UBYTE_TO_FLOAT((p >> 24) ); + } + } + } + break; + case GL_UNSIGNED_INT_10_10_10_2: + if (!intFormat) { + rs = 1.0F / 1023.0F; + gs = 1.0F / 1023.0F; + bs = 1.0F / 1023.0F; + as = 1.0F / 3.0F; + } + if (swapBytes) { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + SWAP4BYTE(p); + rgba[i][rDst] = ((p >> 22) ) * rs; + rgba[i][gDst] = ((p >> 12) & 0x3ff) * gs; + rgba[i][bDst] = ((p >> 2) & 0x3ff) * bs; + rgba[i][aDst] = ((p ) & 0x3 ) * as; + } + } + else { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + rgba[i][rDst] = ((p >> 22) ) * rs; + rgba[i][gDst] = ((p >> 12) & 0x3ff) * gs; + rgba[i][bDst] = ((p >> 2) & 0x3ff) * bs; + rgba[i][aDst] = ((p ) & 0x3 ) * as; + } + } + break; + case GL_UNSIGNED_INT_2_10_10_10_REV: + if (!intFormat) { + rs = 1.0F / 1023.0F; + gs = 1.0F / 1023.0F; + bs = 1.0F / 1023.0F; + as = 1.0F / 3.0F; + } + if (swapBytes) { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + SWAP4BYTE(p); + rgba[i][rDst] = ((p ) & 0x3ff) * rs; + rgba[i][gDst] = ((p >> 10) & 0x3ff) * gs; + rgba[i][bDst] = ((p >> 20) & 0x3ff) * bs; + rgba[i][aDst] = ((p >> 30) ) * as; + } + } + else { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + rgba[i][rDst] = ((p ) & 0x3ff) * rs; + rgba[i][gDst] = ((p >> 10) & 0x3ff) * gs; + rgba[i][bDst] = ((p >> 20) & 0x3ff) * bs; + rgba[i][aDst] = ((p >> 30) ) * as; + } + } + break; + case GL_UNSIGNED_INT_5_9_9_9_REV: + if (swapBytes) { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + GLfloat f[3]; + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + SWAP4BYTE(p); + rgb9e5_to_float3(p, f); + rgba[i][rDst] = f[0]; + rgba[i][gDst] = f[1]; + rgba[i][bDst] = f[2]; + rgba[i][aDst] = 1.0F; + } + } + else { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + GLfloat f[3]; + for (i = 0; i < n; i ++) { + rgb9e5_to_float3(uisrc[i], f); + rgba[i][rDst] = f[0]; + rgba[i][gDst] = f[1]; + rgba[i][bDst] = f[2]; + rgba[i][aDst] = 1.0F; + } + } + break; + case GL_UNSIGNED_INT_10F_11F_11F_REV: + if (swapBytes) { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + GLfloat f[3]; + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + SWAP4BYTE(p); + r11g11b10f_to_float3(p, f); + rgba[i][rDst] = f[0]; + rgba[i][gDst] = f[1]; + rgba[i][bDst] = f[2]; + rgba[i][aDst] = 1.0F; + } + } + else { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + GLfloat f[3]; + for (i = 0; i < n; i ++) { + r11g11b10f_to_float3(uisrc[i], f); + rgba[i][rDst] = f[0]; + rgba[i][gDst] = f[1]; + rgba[i][bDst] = f[2]; + rgba[i][aDst] = 1.0F; + } + } + break; + default: + _mesa_problem(NULL, "bad srcType in extract float data"); + break; + } +#undef PROCESS +} + + +static INLINE GLuint +clamp_byte_to_uint(GLbyte b) +{ + return b < 0 ? 0 : b; +} + + +static INLINE GLuint +clamp_short_to_uint(GLshort s) +{ + return s < 0 ? 0 : s; +} + + +static INLINE GLuint +clamp_int_to_uint(GLint i) +{ + return i < 0 ? 0 : i; +} + + +static INLINE GLuint +clamp_float_to_uint(GLfloat f) +{ + return f < 0.0F ? 0 : IROUND(f); +} + + +static INLINE GLuint +clamp_half_to_uint(GLhalfARB h) +{ + GLfloat f = _mesa_half_to_float(h); + return f < 0.0F ? 0 : IROUND(f); +} + + +/** + * \sa extract_float_rgba() + */ +static void +extract_uint_rgba(GLuint n, GLuint rgba[][4], + GLenum srcFormat, GLenum srcType, const GLvoid *src, + GLboolean swapBytes) +{ + GLint rSrc, gSrc, bSrc, aSrc; + GLint stride; + GLint rDst, bDst, gDst, aDst; + + ASSERT(srcFormat == GL_RED || + srcFormat == GL_GREEN || + srcFormat == GL_BLUE || + srcFormat == GL_ALPHA || + srcFormat == GL_LUMINANCE || + srcFormat == GL_LUMINANCE_ALPHA || + srcFormat == GL_INTENSITY || + srcFormat == GL_RG || + srcFormat == GL_RGB || + srcFormat == GL_BGR || + srcFormat == GL_RGBA || + srcFormat == GL_BGRA || + srcFormat == GL_ABGR_EXT || + srcFormat == GL_DU8DV8_ATI || + srcFormat == GL_DUDV_ATI || + srcFormat == GL_RED_INTEGER_EXT || + srcFormat == GL_GREEN_INTEGER_EXT || + srcFormat == GL_BLUE_INTEGER_EXT || + srcFormat == GL_ALPHA_INTEGER_EXT || + srcFormat == GL_RGB_INTEGER_EXT || + srcFormat == GL_RGBA_INTEGER_EXT || + srcFormat == GL_BGR_INTEGER_EXT || + srcFormat == GL_BGRA_INTEGER_EXT || + srcFormat == GL_LUMINANCE_INTEGER_EXT || + srcFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT); + + ASSERT(srcType == GL_UNSIGNED_BYTE || + srcType == GL_BYTE || + srcType == GL_UNSIGNED_SHORT || + srcType == GL_SHORT || + srcType == GL_UNSIGNED_INT || + srcType == GL_INT || + srcType == GL_HALF_FLOAT_ARB || + srcType == GL_FLOAT || + srcType == GL_UNSIGNED_BYTE_3_3_2 || + srcType == GL_UNSIGNED_BYTE_2_3_3_REV || + srcType == GL_UNSIGNED_SHORT_5_6_5 || + srcType == GL_UNSIGNED_SHORT_5_6_5_REV || + srcType == GL_UNSIGNED_SHORT_4_4_4_4 || + srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV || + srcType == GL_UNSIGNED_SHORT_5_5_5_1 || + srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV || + srcType == GL_UNSIGNED_INT_8_8_8_8 || + srcType == GL_UNSIGNED_INT_8_8_8_8_REV || + srcType == GL_UNSIGNED_INT_10_10_10_2 || + srcType == GL_UNSIGNED_INT_2_10_10_10_REV || + srcType == GL_UNSIGNED_INT_5_9_9_9_REV || + srcType == GL_UNSIGNED_INT_10F_11F_11F_REV); + + get_component_mapping(srcFormat, + &rSrc, &gSrc, &bSrc, &aSrc, + &rDst, &gDst, &bDst, &aDst); + + stride = _mesa_components_in_format(srcFormat); + +#define PROCESS(SRC_INDEX, DST_INDEX, DEFAULT, TYPE, CONVERSION) \ + if ((SRC_INDEX) < 0) { \ + GLuint i; \ + for (i = 0; i < n; i++) { \ + rgba[i][DST_INDEX] = DEFAULT; \ + } \ + } \ + else if (swapBytes) { \ + const TYPE *s = (const TYPE *) src; \ + GLuint i; \ + for (i = 0; i < n; i++) { \ + TYPE value = s[SRC_INDEX]; \ + if (sizeof(TYPE) == 2) { \ + SWAP2BYTE(value); \ + } \ + else if (sizeof(TYPE) == 4) { \ + SWAP4BYTE(value); \ + } \ + rgba[i][DST_INDEX] = CONVERSION(value); \ + s += stride; \ + } \ + } \ + else { \ + const TYPE *s = (const TYPE *) src; \ + GLuint i; \ + for (i = 0; i < n; i++) { \ + rgba[i][DST_INDEX] = CONVERSION(s[SRC_INDEX]); \ + s += stride; \ + } \ + } + + switch (srcType) { + case GL_UNSIGNED_BYTE: + PROCESS(rSrc, RCOMP, 0, GLubyte, (GLuint)); + PROCESS(gSrc, GCOMP, 0, GLubyte, (GLuint)); + PROCESS(bSrc, BCOMP, 0, GLubyte, (GLuint)); + PROCESS(aSrc, ACOMP, 1, GLubyte, (GLuint)); + break; + case GL_BYTE: + PROCESS(rSrc, RCOMP, 0, GLbyte, clamp_byte_to_uint); + PROCESS(gSrc, GCOMP, 0, GLbyte, clamp_byte_to_uint); + PROCESS(bSrc, BCOMP, 0, GLbyte, clamp_byte_to_uint); + PROCESS(aSrc, ACOMP, 1, GLbyte, clamp_byte_to_uint); + break; + case GL_UNSIGNED_SHORT: + PROCESS(rSrc, RCOMP, 0, GLushort, (GLuint)); + PROCESS(gSrc, GCOMP, 0, GLushort, (GLuint)); + PROCESS(bSrc, BCOMP, 0, GLushort, (GLuint)); + PROCESS(aSrc, ACOMP, 1, GLushort, (GLuint)); + break; + case GL_SHORT: + PROCESS(rSrc, RCOMP, 0, GLshort, clamp_short_to_uint); + PROCESS(gSrc, GCOMP, 0, GLshort, clamp_short_to_uint); + PROCESS(bSrc, BCOMP, 0, GLshort, clamp_short_to_uint); + PROCESS(aSrc, ACOMP, 1, GLshort, clamp_short_to_uint); + break; + case GL_UNSIGNED_INT: + PROCESS(rSrc, RCOMP, 0, GLuint, (GLuint)); + PROCESS(gSrc, GCOMP, 0, GLuint, (GLuint)); + PROCESS(bSrc, BCOMP, 0, GLuint, (GLuint)); + PROCESS(aSrc, ACOMP, 1, GLuint, (GLuint)); + break; + case GL_INT: + PROCESS(rSrc, RCOMP, 0, GLint, clamp_int_to_uint); + PROCESS(gSrc, GCOMP, 0, GLint, clamp_int_to_uint); + PROCESS(bSrc, BCOMP, 0, GLint, clamp_int_to_uint); + PROCESS(aSrc, ACOMP, 1, GLint, clamp_int_to_uint); + break; + case GL_FLOAT: + PROCESS(rSrc, RCOMP, 0, GLfloat, clamp_float_to_uint); + PROCESS(gSrc, GCOMP, 0, GLfloat, clamp_float_to_uint); + PROCESS(bSrc, BCOMP, 0, GLfloat, clamp_float_to_uint); + PROCESS(aSrc, ACOMP, 1, GLfloat, clamp_float_to_uint); + break; + case GL_HALF_FLOAT_ARB: + PROCESS(rSrc, RCOMP, 0, GLhalfARB, clamp_half_to_uint); + PROCESS(gSrc, GCOMP, 0, GLhalfARB, clamp_half_to_uint); + PROCESS(bSrc, BCOMP, 0, GLhalfARB, clamp_half_to_uint); + PROCESS(aSrc, ACOMP, 1, GLhalfARB, clamp_half_to_uint); + break; + case GL_UNSIGNED_BYTE_3_3_2: + { + const GLubyte *ubsrc = (const GLubyte *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLubyte p = ubsrc[i]; + rgba[i][rDst] = ((p >> 5) ); + rgba[i][gDst] = ((p >> 2) & 0x7); + rgba[i][bDst] = ((p ) & 0x3); + rgba[i][aDst] = 1; + } + } + break; + case GL_UNSIGNED_BYTE_2_3_3_REV: + { + const GLubyte *ubsrc = (const GLubyte *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLubyte p = ubsrc[i]; + rgba[i][rDst] = ((p ) & 0x7); + rgba[i][gDst] = ((p >> 3) & 0x7); + rgba[i][bDst] = ((p >> 6) ); + rgba[i][aDst] = 1; + } + } + break; + case GL_UNSIGNED_SHORT_5_6_5: + if (swapBytes) { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + SWAP2BYTE(p); + rgba[i][rDst] = ((p >> 11) ); + rgba[i][gDst] = ((p >> 5) & 0x3f); + rgba[i][bDst] = ((p ) & 0x1f); + rgba[i][aDst] = 1; + } + } + else { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + rgba[i][rDst] = ((p >> 11) ); + rgba[i][gDst] = ((p >> 5) & 0x3f); + rgba[i][bDst] = ((p ) & 0x1f); + rgba[i][aDst] = 1; + } + } + break; + case GL_UNSIGNED_SHORT_5_6_5_REV: + if (swapBytes) { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + SWAP2BYTE(p); + rgba[i][rDst] = ((p ) & 0x1f); + rgba[i][gDst] = ((p >> 5) & 0x3f); + rgba[i][bDst] = ((p >> 11) ); + rgba[i][aDst] = 1; + } + } + else { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + rgba[i][rDst] = ((p ) & 0x1f); + rgba[i][gDst] = ((p >> 5) & 0x3f); + rgba[i][bDst] = ((p >> 11) ); + rgba[i][aDst] = 1; + } + } + break; + case GL_UNSIGNED_SHORT_4_4_4_4: + if (swapBytes) { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + SWAP2BYTE(p); + rgba[i][rDst] = ((p >> 12) ); + rgba[i][gDst] = ((p >> 8) & 0xf); + rgba[i][bDst] = ((p >> 4) & 0xf); + rgba[i][aDst] = ((p ) & 0xf); + } + } + else { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + rgba[i][rDst] = ((p >> 12) ); + rgba[i][gDst] = ((p >> 8) & 0xf); + rgba[i][bDst] = ((p >> 4) & 0xf); + rgba[i][aDst] = ((p ) & 0xf); + } + } + break; + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + if (swapBytes) { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + SWAP2BYTE(p); + rgba[i][rDst] = ((p ) & 0xf); + rgba[i][gDst] = ((p >> 4) & 0xf); + rgba[i][bDst] = ((p >> 8) & 0xf); + rgba[i][aDst] = ((p >> 12) ); + } + } + else { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + rgba[i][rDst] = ((p ) & 0xf); + rgba[i][gDst] = ((p >> 4) & 0xf); + rgba[i][bDst] = ((p >> 8) & 0xf); + rgba[i][aDst] = ((p >> 12) ); + } + } + break; + case GL_UNSIGNED_SHORT_5_5_5_1: + if (swapBytes) { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + SWAP2BYTE(p); + rgba[i][rDst] = ((p >> 11) ); + rgba[i][gDst] = ((p >> 6) & 0x1f); + rgba[i][bDst] = ((p >> 1) & 0x1f); + rgba[i][aDst] = ((p ) & 0x1 ); + } + } + else { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + rgba[i][rDst] = ((p >> 11) ); + rgba[i][gDst] = ((p >> 6) & 0x1f); + rgba[i][bDst] = ((p >> 1) & 0x1f); + rgba[i][aDst] = ((p ) & 0x1 ); + } + } + break; + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + if (swapBytes) { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + SWAP2BYTE(p); + rgba[i][rDst] = ((p ) & 0x1f); + rgba[i][gDst] = ((p >> 5) & 0x1f); + rgba[i][bDst] = ((p >> 10) & 0x1f); + rgba[i][aDst] = ((p >> 15) ); + } + } + else { + const GLushort *ussrc = (const GLushort *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLushort p = ussrc[i]; + rgba[i][rDst] = ((p ) & 0x1f); + rgba[i][gDst] = ((p >> 5) & 0x1f); + rgba[i][bDst] = ((p >> 10) & 0x1f); + rgba[i][aDst] = ((p >> 15) ); + } + } + break; + case GL_UNSIGNED_INT_8_8_8_8: + if (swapBytes) { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + rgba[i][rDst] = ((p ) & 0xff); + rgba[i][gDst] = ((p >> 8) & 0xff); + rgba[i][bDst] = ((p >> 16) & 0xff); + rgba[i][aDst] = ((p >> 24) ); + } + } + else { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + rgba[i][rDst] = ((p >> 24) ); + rgba[i][gDst] = ((p >> 16) & 0xff); + rgba[i][bDst] = ((p >> 8) & 0xff); + rgba[i][aDst] = ((p ) & 0xff); + } + } + break; + case GL_UNSIGNED_INT_8_8_8_8_REV: + if (swapBytes) { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + rgba[i][rDst] = ((p >> 24) ); + rgba[i][gDst] = ((p >> 16) & 0xff); + rgba[i][bDst] = ((p >> 8) & 0xff); + rgba[i][aDst] = ((p ) & 0xff); + } + } + else { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + rgba[i][rDst] = ((p ) & 0xff); + rgba[i][gDst] = ((p >> 8) & 0xff); + rgba[i][bDst] = ((p >> 16) & 0xff); + rgba[i][aDst] = ((p >> 24) ); + } + } + break; + case GL_UNSIGNED_INT_10_10_10_2: + if (swapBytes) { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + SWAP4BYTE(p); + rgba[i][rDst] = ((p >> 22) ); + rgba[i][gDst] = ((p >> 12) & 0x3ff); + rgba[i][bDst] = ((p >> 2) & 0x3ff); + rgba[i][aDst] = ((p ) & 0x3 ); + } + } + else { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + rgba[i][rDst] = ((p >> 22) ); + rgba[i][gDst] = ((p >> 12) & 0x3ff); + rgba[i][bDst] = ((p >> 2) & 0x3ff); + rgba[i][aDst] = ((p ) & 0x3 ); + } + } + break; + case GL_UNSIGNED_INT_2_10_10_10_REV: + if (swapBytes) { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + SWAP4BYTE(p); + rgba[i][rDst] = ((p ) & 0x3ff); + rgba[i][gDst] = ((p >> 10) & 0x3ff); + rgba[i][bDst] = ((p >> 20) & 0x3ff); + rgba[i][aDst] = ((p >> 30) ); + } + } + else { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + rgba[i][rDst] = ((p ) & 0x3ff); + rgba[i][gDst] = ((p >> 10) & 0x3ff); + rgba[i][bDst] = ((p >> 20) & 0x3ff); + rgba[i][aDst] = ((p >> 30) ); + } + } + break; + case GL_UNSIGNED_INT_5_9_9_9_REV: + if (swapBytes) { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + float f[3]; + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + SWAP4BYTE(p); + rgb9e5_to_float3(p, f); + rgba[i][rDst] = clamp_float_to_uint(f[0]); + rgba[i][gDst] = clamp_float_to_uint(f[1]); + rgba[i][bDst] = clamp_float_to_uint(f[2]); + rgba[i][aDst] = 1; + } + } + else { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + float f[3]; + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + rgb9e5_to_float3(p, f); + rgba[i][rDst] = clamp_float_to_uint(f[0]); + rgba[i][gDst] = clamp_float_to_uint(f[1]); + rgba[i][bDst] = clamp_float_to_uint(f[2]); + rgba[i][aDst] = 1; + } + } + break; + case GL_UNSIGNED_INT_10F_11F_11F_REV: + if (swapBytes) { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + float f[3]; + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + SWAP4BYTE(p); + r11g11b10f_to_float3(p, f); + rgba[i][rDst] = clamp_float_to_uint(f[0]); + rgba[i][gDst] = clamp_float_to_uint(f[1]); + rgba[i][bDst] = clamp_float_to_uint(f[2]); + rgba[i][aDst] = 1; + } + } + else { + const GLuint *uisrc = (const GLuint *) src; + GLuint i; + float f[3]; + for (i = 0; i < n; i ++) { + GLuint p = uisrc[i]; + r11g11b10f_to_float3(p, f); + rgba[i][rDst] = clamp_float_to_uint(f[0]); + rgba[i][gDst] = clamp_float_to_uint(f[1]); + rgba[i][bDst] = clamp_float_to_uint(f[2]); + rgba[i][aDst] = 1; + } + } + break; + default: + _mesa_problem(NULL, "bad srcType in extract uint data"); + break; + } +#undef PROCESS +} + + + +/* + * Unpack a row of color image data from a client buffer according to + * the pixel unpacking parameters. + * Return GLchan values in the specified dest image format. + * This is used by glDrawPixels and glTexImage?D(). + * \param ctx - the context + * n - number of pixels in the span + * dstFormat - format of destination color array + * dest - the destination color array + * srcFormat - source image format + * srcType - source image data type + * source - source image pointer + * srcPacking - pixel unpacking parameters + * transferOps - bitmask of IMAGE_*_BIT values of operations to apply + * + * XXX perhaps expand this to process whole images someday. + */ +void +_mesa_unpack_color_span_chan( struct gl_context *ctx, + GLuint n, GLenum dstFormat, GLchan dest[], + GLenum srcFormat, GLenum srcType, + const GLvoid *source, + const struct gl_pixelstore_attrib *srcPacking, + GLbitfield transferOps ) +{ + ASSERT(dstFormat == GL_ALPHA || + dstFormat == GL_LUMINANCE || + dstFormat == GL_LUMINANCE_ALPHA || + dstFormat == GL_INTENSITY || + dstFormat == GL_RED || + dstFormat == GL_RG || + dstFormat == GL_RGB || + dstFormat == GL_RGBA || + dstFormat == GL_COLOR_INDEX); + + ASSERT(srcFormat == GL_RED || + srcFormat == GL_GREEN || + srcFormat == GL_BLUE || + srcFormat == GL_ALPHA || + srcFormat == GL_LUMINANCE || + srcFormat == GL_LUMINANCE_ALPHA || + srcFormat == GL_INTENSITY || + srcFormat == GL_RG || + srcFormat == GL_RGB || + srcFormat == GL_BGR || + srcFormat == GL_RGBA || + srcFormat == GL_BGRA || + srcFormat == GL_ABGR_EXT || + srcFormat == GL_COLOR_INDEX); + + ASSERT(srcType == GL_BITMAP || + srcType == GL_UNSIGNED_BYTE || + srcType == GL_BYTE || + srcType == GL_UNSIGNED_SHORT || + srcType == GL_SHORT || + srcType == GL_UNSIGNED_INT || + srcType == GL_INT || + srcType == GL_HALF_FLOAT_ARB || + srcType == GL_FLOAT || + srcType == GL_UNSIGNED_BYTE_3_3_2 || + srcType == GL_UNSIGNED_BYTE_2_3_3_REV || + srcType == GL_UNSIGNED_SHORT_5_6_5 || + srcType == GL_UNSIGNED_SHORT_5_6_5_REV || + srcType == GL_UNSIGNED_SHORT_4_4_4_4 || + srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV || + srcType == GL_UNSIGNED_SHORT_5_5_5_1 || + srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV || + srcType == GL_UNSIGNED_INT_8_8_8_8 || + srcType == GL_UNSIGNED_INT_8_8_8_8_REV || + srcType == GL_UNSIGNED_INT_10_10_10_2 || + srcType == GL_UNSIGNED_INT_2_10_10_10_REV || + srcType == GL_UNSIGNED_INT_5_9_9_9_REV || + srcType == GL_UNSIGNED_INT_10F_11F_11F_REV); + + /* Try simple cases first */ + if (transferOps == 0) { + if (srcType == CHAN_TYPE) { + if (dstFormat == GL_RGBA) { + if (srcFormat == GL_RGBA) { + memcpy( dest, source, n * 4 * sizeof(GLchan) ); + return; + } + else if (srcFormat == GL_RGB) { + GLuint i; + const GLchan *src = (const GLchan *) source; + GLchan *dst = dest; + for (i = 0; i < n; i++) { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = CHAN_MAX; + src += 3; + dst += 4; + } + return; + } + } + else if (dstFormat == GL_RGB) { + if (srcFormat == GL_RGB) { + memcpy( dest, source, n * 3 * sizeof(GLchan) ); + return; + } + else if (srcFormat == GL_RGBA) { + GLuint i; + const GLchan *src = (const GLchan *) source; + GLchan *dst = dest; + for (i = 0; i < n; i++) { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + src += 4; + dst += 3; + } + return; + } + } + else if (dstFormat == srcFormat) { + GLint comps = _mesa_components_in_format(srcFormat); + assert(comps > 0); + memcpy( dest, source, n * comps * sizeof(GLchan) ); + return; + } + } + /* + * Common situation, loading 8bit RGBA/RGB source images + * into 16/32 bit destination. (OSMesa16/32) + */ + else if (srcType == GL_UNSIGNED_BYTE) { + if (dstFormat == GL_RGBA) { + if (srcFormat == GL_RGB) { + GLuint i; + const GLubyte *src = (const GLubyte *) source; + GLchan *dst = dest; + for (i = 0; i < n; i++) { + dst[0] = UBYTE_TO_CHAN(src[0]); + dst[1] = UBYTE_TO_CHAN(src[1]); + dst[2] = UBYTE_TO_CHAN(src[2]); + dst[3] = CHAN_MAX; + src += 3; + dst += 4; + } + return; + } + else if (srcFormat == GL_RGBA) { + GLuint i; + const GLubyte *src = (const GLubyte *) source; + GLchan *dst = dest; + for (i = 0; i < n; i++) { + dst[0] = UBYTE_TO_CHAN(src[0]); + dst[1] = UBYTE_TO_CHAN(src[1]); + dst[2] = UBYTE_TO_CHAN(src[2]); + dst[3] = UBYTE_TO_CHAN(src[3]); + src += 4; + dst += 4; + } + return; + } + } + else if (dstFormat == GL_RGB) { + if (srcFormat == GL_RGB) { + GLuint i; + const GLubyte *src = (const GLubyte *) source; + GLchan *dst = dest; + for (i = 0; i < n; i++) { + dst[0] = UBYTE_TO_CHAN(src[0]); + dst[1] = UBYTE_TO_CHAN(src[1]); + dst[2] = UBYTE_TO_CHAN(src[2]); + src += 3; + dst += 3; + } + return; + } + else if (srcFormat == GL_RGBA) { + GLuint i; + const GLubyte *src = (const GLubyte *) source; + GLchan *dst = dest; + for (i = 0; i < n; i++) { + dst[0] = UBYTE_TO_CHAN(src[0]); + dst[1] = UBYTE_TO_CHAN(src[1]); + dst[2] = UBYTE_TO_CHAN(src[2]); + src += 4; + dst += 3; + } + return; + } + } + } + } + + + /* general solution begins here */ + { + GLint dstComponents; + GLint rDst, gDst, bDst, aDst, lDst, iDst; + GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat)); + + if (!rgba) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); + return; + } + + dstComponents = _mesa_components_in_format( dstFormat ); + /* source & dest image formats should have been error checked by now */ + assert(dstComponents > 0); + + /* + * Extract image data and convert to RGBA floats + */ + if (srcFormat == GL_COLOR_INDEX) { + GLuint *indexes = (GLuint *) malloc(n * sizeof(GLuint)); + + if (!indexes) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); + return; + } + + extract_uint_indexes(n, indexes, srcFormat, srcType, source, + srcPacking); + + if (dstFormat == GL_COLOR_INDEX) { + GLuint i; + _mesa_apply_ci_transfer_ops(ctx, transferOps, n, indexes); + /* convert to GLchan and return */ + for (i = 0; i < n; i++) { + dest[i] = (GLchan) (indexes[i] & 0xff); + } + free(indexes); + free(rgba); + return; + } + else { + /* Convert indexes to RGBA */ + if (transferOps & IMAGE_SHIFT_OFFSET_BIT) { + _mesa_shift_and_offset_ci(ctx, n, indexes); + } + _mesa_map_ci_to_rgba(ctx, n, indexes, rgba); + } + + /* Don't do RGBA scale/bias or RGBA->RGBA mapping if starting + * with color indexes. + */ + transferOps &= ~(IMAGE_SCALE_BIAS_BIT | IMAGE_MAP_COLOR_BIT); + + free(indexes); + } + else { + /* non-color index data */ + extract_float_rgba(n, rgba, srcFormat, srcType, source, + srcPacking->SwapBytes); + } + + /* Need to clamp if returning GLubytes or GLushorts */ +#if CHAN_TYPE != GL_FLOAT + transferOps |= IMAGE_CLAMP_BIT; +#endif + + if (transferOps) { + _mesa_apply_rgba_transfer_ops(ctx, transferOps, n, rgba); + } + + get_component_indexes(dstFormat, + &rDst, &gDst, &bDst, &aDst, &lDst, &iDst); + + /* Now return the GLchan data in the requested dstFormat */ + if (rDst >= 0) { + GLchan *dst = dest; + GLuint i; + for (i = 0; i < n; i++) { + CLAMPED_FLOAT_TO_CHAN(dst[rDst], rgba[i][RCOMP]); + dst += dstComponents; + } + } + + if (gDst >= 0) { + GLchan *dst = dest; + GLuint i; + for (i = 0; i < n; i++) { + CLAMPED_FLOAT_TO_CHAN(dst[gDst], rgba[i][GCOMP]); + dst += dstComponents; + } + } + + if (bDst >= 0) { + GLchan *dst = dest; + GLuint i; + for (i = 0; i < n; i++) { + CLAMPED_FLOAT_TO_CHAN(dst[bDst], rgba[i][BCOMP]); + dst += dstComponents; + } + } + + if (aDst >= 0) { + GLchan *dst = dest; + GLuint i; + for (i = 0; i < n; i++) { + CLAMPED_FLOAT_TO_CHAN(dst[aDst], rgba[i][ACOMP]); + dst += dstComponents; + } + } + + if (iDst >= 0) { + GLchan *dst = dest; + GLuint i; + assert(iDst == 0); + assert(dstComponents == 1); + for (i = 0; i < n; i++) { + /* Intensity comes from red channel */ + CLAMPED_FLOAT_TO_CHAN(dst[i], rgba[i][RCOMP]); + } + } + + if (lDst >= 0) { + GLchan *dst = dest; + GLuint i; + assert(lDst == 0); + for (i = 0; i < n; i++) { + /* Luminance comes from red channel */ + CLAMPED_FLOAT_TO_CHAN(dst[0], rgba[i][RCOMP]); + dst += dstComponents; + } + } + + free(rgba); + } +} + + +/** + * Same as _mesa_unpack_color_span_chan(), but return GLfloat data + * instead of GLchan. + */ +void +_mesa_unpack_color_span_float( struct gl_context *ctx, + GLuint n, GLenum dstFormat, GLfloat dest[], + GLenum srcFormat, GLenum srcType, + const GLvoid *source, + const struct gl_pixelstore_attrib *srcPacking, + GLbitfield transferOps ) +{ + ASSERT(dstFormat == GL_ALPHA || + dstFormat == GL_LUMINANCE || + dstFormat == GL_LUMINANCE_ALPHA || + dstFormat == GL_INTENSITY || + dstFormat == GL_RED || + dstFormat == GL_RG || + dstFormat == GL_RGB || + dstFormat == GL_RGBA || + dstFormat == GL_COLOR_INDEX); + + ASSERT(srcFormat == GL_RED || + srcFormat == GL_GREEN || + srcFormat == GL_BLUE || + srcFormat == GL_ALPHA || + srcFormat == GL_LUMINANCE || + srcFormat == GL_LUMINANCE_ALPHA || + srcFormat == GL_INTENSITY || + srcFormat == GL_RG || + srcFormat == GL_RGB || + srcFormat == GL_BGR || + srcFormat == GL_RGBA || + srcFormat == GL_BGRA || + srcFormat == GL_ABGR_EXT || + srcFormat == GL_RED_INTEGER_EXT || + srcFormat == GL_GREEN_INTEGER_EXT || + srcFormat == GL_BLUE_INTEGER_EXT || + srcFormat == GL_ALPHA_INTEGER_EXT || + srcFormat == GL_RGB_INTEGER_EXT || + srcFormat == GL_RGBA_INTEGER_EXT || + srcFormat == GL_BGR_INTEGER_EXT || + srcFormat == GL_BGRA_INTEGER_EXT || + srcFormat == GL_LUMINANCE_INTEGER_EXT || + srcFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT || + srcFormat == GL_COLOR_INDEX); + + ASSERT(srcType == GL_BITMAP || + srcType == GL_UNSIGNED_BYTE || + srcType == GL_BYTE || + srcType == GL_UNSIGNED_SHORT || + srcType == GL_SHORT || + srcType == GL_UNSIGNED_INT || + srcType == GL_INT || + srcType == GL_HALF_FLOAT_ARB || + srcType == GL_FLOAT || + srcType == GL_UNSIGNED_BYTE_3_3_2 || + srcType == GL_UNSIGNED_BYTE_2_3_3_REV || + srcType == GL_UNSIGNED_SHORT_5_6_5 || + srcType == GL_UNSIGNED_SHORT_5_6_5_REV || + srcType == GL_UNSIGNED_SHORT_4_4_4_4 || + srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV || + srcType == GL_UNSIGNED_SHORT_5_5_5_1 || + srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV || + srcType == GL_UNSIGNED_INT_8_8_8_8 || + srcType == GL_UNSIGNED_INT_8_8_8_8_REV || + srcType == GL_UNSIGNED_INT_10_10_10_2 || + srcType == GL_UNSIGNED_INT_2_10_10_10_REV || + srcType == GL_UNSIGNED_INT_5_9_9_9_REV || + srcType == GL_UNSIGNED_INT_10F_11F_11F_REV); + + /* general solution, no special cases, yet */ + { + GLint dstComponents; + GLint rDst, gDst, bDst, aDst, lDst, iDst; + GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat)); + + if (!rgba) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); + return; + } + + dstComponents = _mesa_components_in_format( dstFormat ); + /* source & dest image formats should have been error checked by now */ + assert(dstComponents > 0); + + /* + * Extract image data and convert to RGBA floats + */ + if (srcFormat == GL_COLOR_INDEX) { + GLuint *indexes = (GLuint *) malloc(n * sizeof(GLuint)); + + if (!indexes) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); + free(rgba); + return; + } + + extract_uint_indexes(n, indexes, srcFormat, srcType, source, + srcPacking); + + if (dstFormat == GL_COLOR_INDEX) { + GLuint i; + _mesa_apply_ci_transfer_ops(ctx, transferOps, n, indexes); + /* convert to GLchan and return */ + for (i = 0; i < n; i++) { + dest[i] = (GLchan) (indexes[i] & 0xff); + } + free(indexes); + free(rgba); + return; + } + else { + /* Convert indexes to RGBA */ + if (transferOps & IMAGE_SHIFT_OFFSET_BIT) { + _mesa_shift_and_offset_ci(ctx, n, indexes); + } + _mesa_map_ci_to_rgba(ctx, n, indexes, rgba); + } + + /* Don't do RGBA scale/bias or RGBA->RGBA mapping if starting + * with color indexes. + */ + transferOps &= ~(IMAGE_SCALE_BIAS_BIT | IMAGE_MAP_COLOR_BIT); + + free(indexes); + } + else { + /* non-color index data */ + extract_float_rgba(n, rgba, srcFormat, srcType, source, + srcPacking->SwapBytes); + } + + if (transferOps) { + _mesa_apply_rgba_transfer_ops(ctx, transferOps, n, rgba); + } + + get_component_indexes(dstFormat, + &rDst, &gDst, &bDst, &aDst, &lDst, &iDst); + + /* Now pack results in the requested dstFormat */ + if (rDst >= 0) { + GLfloat *dst = dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[rDst] = rgba[i][RCOMP]; + dst += dstComponents; + } + } + + if (gDst >= 0) { + GLfloat *dst = dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[gDst] = rgba[i][GCOMP]; + dst += dstComponents; + } + } + + if (bDst >= 0) { + GLfloat *dst = dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[bDst] = rgba[i][BCOMP]; + dst += dstComponents; + } + } + + if (aDst >= 0) { + GLfloat *dst = dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[aDst] = rgba[i][ACOMP]; + dst += dstComponents; + } + } + + if (iDst >= 0) { + GLfloat *dst = dest; + GLuint i; + assert(iDst == 0); + assert(dstComponents == 1); + for (i = 0; i < n; i++) { + /* Intensity comes from red channel */ + dst[i] = rgba[i][RCOMP]; + } + } + + if (lDst >= 0) { + GLfloat *dst = dest; + GLuint i; + assert(lDst == 0); + for (i = 0; i < n; i++) { + /* Luminance comes from red channel */ + dst[0] = rgba[i][RCOMP]; + dst += dstComponents; + } + } + + free(rgba); + } +} + + +/** + * Same as _mesa_unpack_color_span_chan(), but return GLuint data + * instead of GLchan. + * No pixel transfer ops are applied. + */ +void +_mesa_unpack_color_span_uint(struct gl_context *ctx, + GLuint n, GLenum dstFormat, GLuint *dest, + GLenum srcFormat, GLenum srcType, + const GLvoid *source, + const struct gl_pixelstore_attrib *srcPacking) +{ + GLuint (*rgba)[4] = (GLuint (*)[4]) malloc(n * 4 * sizeof(GLfloat)); + + if (!rgba) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); + return; + } + + ASSERT(dstFormat == GL_ALPHA || + dstFormat == GL_LUMINANCE || + dstFormat == GL_LUMINANCE_ALPHA || + dstFormat == GL_INTENSITY || + dstFormat == GL_RED || + dstFormat == GL_RG || + dstFormat == GL_RGB || + dstFormat == GL_RGBA); + + ASSERT(srcFormat == GL_RED || + srcFormat == GL_GREEN || + srcFormat == GL_BLUE || + srcFormat == GL_ALPHA || + srcFormat == GL_LUMINANCE || + srcFormat == GL_LUMINANCE_ALPHA || + srcFormat == GL_INTENSITY || + srcFormat == GL_RG || + srcFormat == GL_RGB || + srcFormat == GL_BGR || + srcFormat == GL_RGBA || + srcFormat == GL_BGRA || + srcFormat == GL_ABGR_EXT || + srcFormat == GL_RED_INTEGER_EXT || + srcFormat == GL_GREEN_INTEGER_EXT || + srcFormat == GL_BLUE_INTEGER_EXT || + srcFormat == GL_ALPHA_INTEGER_EXT || + srcFormat == GL_RGB_INTEGER_EXT || + srcFormat == GL_RGBA_INTEGER_EXT || + srcFormat == GL_BGR_INTEGER_EXT || + srcFormat == GL_BGRA_INTEGER_EXT || + srcFormat == GL_LUMINANCE_INTEGER_EXT || + srcFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT); + + ASSERT(srcType == GL_UNSIGNED_BYTE || + srcType == GL_BYTE || + srcType == GL_UNSIGNED_SHORT || + srcType == GL_SHORT || + srcType == GL_UNSIGNED_INT || + srcType == GL_INT || + srcType == GL_HALF_FLOAT_ARB || + srcType == GL_FLOAT || + srcType == GL_UNSIGNED_BYTE_3_3_2 || + srcType == GL_UNSIGNED_BYTE_2_3_3_REV || + srcType == GL_UNSIGNED_SHORT_5_6_5 || + srcType == GL_UNSIGNED_SHORT_5_6_5_REV || + srcType == GL_UNSIGNED_SHORT_4_4_4_4 || + srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV || + srcType == GL_UNSIGNED_SHORT_5_5_5_1 || + srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV || + srcType == GL_UNSIGNED_INT_8_8_8_8 || + srcType == GL_UNSIGNED_INT_8_8_8_8_REV || + srcType == GL_UNSIGNED_INT_10_10_10_2 || + srcType == GL_UNSIGNED_INT_2_10_10_10_REV || + srcType == GL_UNSIGNED_INT_5_9_9_9_REV || + srcType == GL_UNSIGNED_INT_10F_11F_11F_REV); + + + /* Extract image data as uint[4] pixels */ + extract_uint_rgba(n, rgba, srcFormat, srcType, source, + srcPacking->SwapBytes); + + if (dstFormat == GL_RGBA) { + /* simple case */ + memcpy(dest, rgba, 4 * sizeof(GLuint) * n); + } + else { + /* general case */ + GLint rDst, gDst, bDst, aDst, lDst, iDst; + GLint dstComponents = _mesa_components_in_format( dstFormat ); + + assert(dstComponents > 0); + + get_component_indexes(dstFormat, + &rDst, &gDst, &bDst, &aDst, &lDst, &iDst); + + /* Now pack values in the requested dest format */ + if (rDst >= 0) { + GLuint *dst = dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[rDst] = rgba[i][RCOMP]; + dst += dstComponents; + } + } + + if (gDst >= 0) { + GLuint *dst = dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[gDst] = rgba[i][GCOMP]; + dst += dstComponents; + } + } + + if (bDst >= 0) { + GLuint *dst = dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[bDst] = rgba[i][BCOMP]; + dst += dstComponents; + } + } + + if (aDst >= 0) { + GLuint *dst = dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[aDst] = rgba[i][ACOMP]; + dst += dstComponents; + } + } + + if (iDst >= 0) { + GLuint *dst = dest; + GLuint i; + assert(iDst == 0); + assert(dstComponents == 1); + for (i = 0; i < n; i++) { + /* Intensity comes from red channel */ + dst[i] = rgba[i][RCOMP]; + } + } + + if (lDst >= 0) { + GLuint *dst = dest; + GLuint i; + assert(lDst == 0); + for (i = 0; i < n; i++) { + /* Luminance comes from red channel */ + dst[0] = rgba[i][RCOMP]; + dst += dstComponents; + } + } + } + + free(rgba); +} + + + +/** + * Similar to _mesa_unpack_color_span_float(), but for dudv data instead of rgba, + * directly return GLbyte data, no transfer ops apply. + */ +void +_mesa_unpack_dudv_span_byte( struct gl_context *ctx, + GLuint n, GLenum dstFormat, GLbyte dest[], + GLenum srcFormat, GLenum srcType, + const GLvoid *source, + const struct gl_pixelstore_attrib *srcPacking, + GLbitfield transferOps ) +{ + ASSERT(dstFormat == GL_DUDV_ATI); + ASSERT(srcFormat == GL_DUDV_ATI || + srcFormat == GL_DU8DV8_ATI); + + ASSERT(srcType == GL_UNSIGNED_BYTE || + srcType == GL_BYTE || + srcType == GL_UNSIGNED_SHORT || + srcType == GL_SHORT || + srcType == GL_UNSIGNED_INT || + srcType == GL_INT || + srcType == GL_HALF_FLOAT_ARB || + srcType == GL_FLOAT); + + /* general solution */ + { + GLint dstComponents; + GLbyte *dst = dest; + GLuint i; + GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat)); + + if (!rgba) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); + return; + } + + dstComponents = _mesa_components_in_format( dstFormat ); + /* source & dest image formats should have been error checked by now */ + assert(dstComponents > 0); + + /* + * Extract image data and convert to RGBA floats + */ + extract_float_rgba(n, rgba, srcFormat, srcType, source, + srcPacking->SwapBytes); + + + /* Now determine which color channels we need to produce. + * And determine the dest index (offset) within each color tuple. + */ + + /* Now pack results in the requested dstFormat */ + for (i = 0; i < n; i++) { + /* not sure - need clamp[-1,1] here? */ + dst[0] = FLOAT_TO_BYTE(rgba[i][RCOMP]); + dst[1] = FLOAT_TO_BYTE(rgba[i][GCOMP]); + dst += dstComponents; + } + + free(rgba); + } +} + +/* + * Unpack a row of color index data from a client buffer according to + * the pixel unpacking parameters. + * This is (or will be) used by glDrawPixels, glTexImage[123]D, etc. + * + * Args: ctx - the context + * n - number of pixels + * dstType - destination data type + * dest - destination array + * srcType - source pixel type + * source - source data pointer + * srcPacking - pixel unpacking parameters + * transferOps - the pixel transfer operations to apply + */ +void +_mesa_unpack_index_span( struct gl_context *ctx, GLuint n, + GLenum dstType, GLvoid *dest, + GLenum srcType, const GLvoid *source, + const struct gl_pixelstore_attrib *srcPacking, + GLbitfield transferOps ) +{ + ASSERT(srcType == GL_BITMAP || + srcType == GL_UNSIGNED_BYTE || + srcType == GL_BYTE || + srcType == GL_UNSIGNED_SHORT || + srcType == GL_SHORT || + srcType == GL_UNSIGNED_INT || + srcType == GL_INT || + srcType == GL_HALF_FLOAT_ARB || + srcType == GL_FLOAT); + + ASSERT(dstType == GL_UNSIGNED_BYTE || + dstType == GL_UNSIGNED_SHORT || + dstType == GL_UNSIGNED_INT); + + + transferOps &= (IMAGE_MAP_COLOR_BIT | IMAGE_SHIFT_OFFSET_BIT); + + /* + * Try simple cases first + */ + if (transferOps == 0 && srcType == GL_UNSIGNED_BYTE + && dstType == GL_UNSIGNED_BYTE) { + memcpy(dest, source, n * sizeof(GLubyte)); + } + else if (transferOps == 0 && srcType == GL_UNSIGNED_INT + && dstType == GL_UNSIGNED_INT && !srcPacking->SwapBytes) { + memcpy(dest, source, n * sizeof(GLuint)); + } + else { + /* + * general solution + */ + GLuint *indexes = (GLuint *) malloc(n * sizeof(GLuint)); + + if (!indexes) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); + return; + } + + extract_uint_indexes(n, indexes, GL_COLOR_INDEX, srcType, source, + srcPacking); + + if (transferOps) + _mesa_apply_ci_transfer_ops(ctx, transferOps, n, indexes); + + /* convert to dest type */ + switch (dstType) { + case GL_UNSIGNED_BYTE: + { + GLubyte *dst = (GLubyte *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = (GLubyte) (indexes[i] & 0xff); + } + } + break; + case GL_UNSIGNED_SHORT: + { + GLuint *dst = (GLuint *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = (GLushort) (indexes[i] & 0xffff); + } + } + break; + case GL_UNSIGNED_INT: + memcpy(dest, indexes, n * sizeof(GLuint)); + break; + default: + _mesa_problem(ctx, "bad dstType in _mesa_unpack_index_span"); + } + + free(indexes); + } +} + + +void +_mesa_pack_index_span( struct gl_context *ctx, GLuint n, + GLenum dstType, GLvoid *dest, const GLuint *source, + const struct gl_pixelstore_attrib *dstPacking, + GLbitfield transferOps ) +{ + GLuint *indexes = (GLuint *) malloc(n * sizeof(GLuint)); + + if (!indexes) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel packing"); + return; + } + + transferOps &= (IMAGE_MAP_COLOR_BIT | IMAGE_SHIFT_OFFSET_BIT); + + if (transferOps & (IMAGE_MAP_COLOR_BIT | IMAGE_SHIFT_OFFSET_BIT)) { + /* make a copy of input */ + memcpy(indexes, source, n * sizeof(GLuint)); + _mesa_apply_ci_transfer_ops(ctx, transferOps, n, indexes); + source = indexes; + } + + switch (dstType) { + case GL_UNSIGNED_BYTE: + { + GLubyte *dst = (GLubyte *) dest; + GLuint i; + for (i = 0; i < n; i++) { + *dst++ = (GLubyte) source[i]; + } + } + break; + case GL_BYTE: + { + GLbyte *dst = (GLbyte *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = (GLbyte) source[i]; + } + } + break; + case GL_UNSIGNED_SHORT: + { + GLushort *dst = (GLushort *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = (GLushort) source[i]; + } + if (dstPacking->SwapBytes) { + _mesa_swap2( (GLushort *) dst, n ); + } + } + break; + case GL_SHORT: + { + GLshort *dst = (GLshort *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = (GLshort) source[i]; + } + if (dstPacking->SwapBytes) { + _mesa_swap2( (GLushort *) dst, n ); + } + } + break; + case GL_UNSIGNED_INT: + { + GLuint *dst = (GLuint *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = (GLuint) source[i]; + } + if (dstPacking->SwapBytes) { + _mesa_swap4( (GLuint *) dst, n ); + } + } + break; + case GL_INT: + { + GLint *dst = (GLint *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = (GLint) source[i]; + } + if (dstPacking->SwapBytes) { + _mesa_swap4( (GLuint *) dst, n ); + } + } + break; + case GL_FLOAT: + { + GLfloat *dst = (GLfloat *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = (GLfloat) source[i]; + } + if (dstPacking->SwapBytes) { + _mesa_swap4( (GLuint *) dst, n ); + } + } + break; + case GL_HALF_FLOAT_ARB: + { + GLhalfARB *dst = (GLhalfARB *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = _mesa_float_to_half((GLfloat) source[i]); + } + if (dstPacking->SwapBytes) { + _mesa_swap2( (GLushort *) dst, n ); + } + } + break; + default: + _mesa_problem(ctx, "bad type in _mesa_pack_index_span"); + } + + free(indexes); +} + + +/* + * Unpack a row of stencil data from a client buffer according to + * the pixel unpacking parameters. + * This is (or will be) used by glDrawPixels + * + * Args: ctx - the context + * n - number of pixels + * dstType - destination data type + * dest - destination array + * srcType - source pixel type + * source - source data pointer + * srcPacking - pixel unpacking parameters + * transferOps - apply offset/bias/lookup ops? + */ +void +_mesa_unpack_stencil_span( struct gl_context *ctx, GLuint n, + GLenum dstType, GLvoid *dest, + GLenum srcType, const GLvoid *source, + const struct gl_pixelstore_attrib *srcPacking, + GLbitfield transferOps ) +{ + ASSERT(srcType == GL_BITMAP || + srcType == GL_UNSIGNED_BYTE || + srcType == GL_BYTE || + srcType == GL_UNSIGNED_SHORT || + srcType == GL_SHORT || + srcType == GL_UNSIGNED_INT || + srcType == GL_INT || + srcType == GL_UNSIGNED_INT_24_8_EXT || + srcType == GL_HALF_FLOAT_ARB || + srcType == GL_FLOAT); + + ASSERT(dstType == GL_UNSIGNED_BYTE || + dstType == GL_UNSIGNED_SHORT || + dstType == GL_UNSIGNED_INT); + + /* only shift and offset apply to stencil */ + transferOps &= IMAGE_SHIFT_OFFSET_BIT; + + /* + * Try simple cases first + */ + if (transferOps == 0 && + !ctx->Pixel.MapStencilFlag && + srcType == GL_UNSIGNED_BYTE && + dstType == GL_UNSIGNED_BYTE) { + memcpy(dest, source, n * sizeof(GLubyte)); + } + else if (transferOps == 0 && + !ctx->Pixel.MapStencilFlag && + srcType == GL_UNSIGNED_INT && + dstType == GL_UNSIGNED_INT && + !srcPacking->SwapBytes) { + memcpy(dest, source, n * sizeof(GLuint)); + } + else { + /* + * general solution + */ + GLuint *indexes = (GLuint *) malloc(n * sizeof(GLuint)); + + if (!indexes) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "stencil unpacking"); + return; + } + + extract_uint_indexes(n, indexes, GL_STENCIL_INDEX, srcType, source, + srcPacking); + + if (transferOps & IMAGE_SHIFT_OFFSET_BIT) { + /* shift and offset indexes */ + _mesa_shift_and_offset_ci(ctx, n, indexes); + } + + if (ctx->Pixel.MapStencilFlag) { + /* Apply stencil lookup table */ + const GLuint mask = ctx->PixelMaps.StoS.Size - 1; + GLuint i; + for (i = 0; i < n; i++) { + indexes[i] = (GLuint)ctx->PixelMaps.StoS.Map[ indexes[i] & mask ]; + } + } + + /* convert to dest type */ + switch (dstType) { + case GL_UNSIGNED_BYTE: + { + GLubyte *dst = (GLubyte *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = (GLubyte) (indexes[i] & 0xff); + } + } + break; + case GL_UNSIGNED_SHORT: + { + GLuint *dst = (GLuint *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = (GLushort) (indexes[i] & 0xffff); + } + } + break; + case GL_UNSIGNED_INT: + memcpy(dest, indexes, n * sizeof(GLuint)); + break; + default: + _mesa_problem(ctx, "bad dstType in _mesa_unpack_stencil_span"); + } + + free(indexes); + } +} + + +void +_mesa_pack_stencil_span( struct gl_context *ctx, GLuint n, + GLenum dstType, GLvoid *dest, const GLstencil *source, + const struct gl_pixelstore_attrib *dstPacking ) +{ + GLstencil *stencil = (GLstencil *) malloc(n * sizeof(GLstencil)); + + if (!stencil) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "stencil packing"); + return; + } + + if (ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset || + ctx->Pixel.MapStencilFlag) { + /* make a copy of input */ + memcpy(stencil, source, n * sizeof(GLstencil)); + _mesa_apply_stencil_transfer_ops(ctx, n, stencil); + source = stencil; + } + + switch (dstType) { + case GL_UNSIGNED_BYTE: + if (sizeof(GLstencil) == 1) { + memcpy( dest, source, n ); + } + else { + GLubyte *dst = (GLubyte *) dest; + GLuint i; + for (i=0;iSwapBytes) { + _mesa_swap2( (GLushort *) dst, n ); + } + } + break; + case GL_SHORT: + { + GLshort *dst = (GLshort *) dest; + GLuint i; + for (i=0;iSwapBytes) { + _mesa_swap2( (GLushort *) dst, n ); + } + } + break; + case GL_UNSIGNED_INT: + { + GLuint *dst = (GLuint *) dest; + GLuint i; + for (i=0;iSwapBytes) { + _mesa_swap4( (GLuint *) dst, n ); + } + } + break; + case GL_INT: + { + GLint *dst = (GLint *) dest; + GLuint i; + for (i=0;iSwapBytes) { + _mesa_swap4( (GLuint *) dst, n ); + } + } + break; + case GL_FLOAT: + { + GLfloat *dst = (GLfloat *) dest; + GLuint i; + for (i=0;iSwapBytes) { + _mesa_swap4( (GLuint *) dst, n ); + } + } + break; + case GL_HALF_FLOAT_ARB: + { + GLhalfARB *dst = (GLhalfARB *) dest; + GLuint i; + for (i=0;iSwapBytes) { + _mesa_swap2( (GLushort *) dst, n ); + } + } + break; + case GL_BITMAP: + if (dstPacking->LsbFirst) { + GLubyte *dst = (GLubyte *) dest; + GLint shift = 0; + GLuint i; + for (i = 0; i < n; i++) { + if (shift == 0) + *dst = 0; + *dst |= ((source[i] != 0) << shift); + shift++; + if (shift == 8) { + shift = 0; + dst++; + } + } + } + else { + GLubyte *dst = (GLubyte *) dest; + GLint shift = 7; + GLuint i; + for (i = 0; i < n; i++) { + if (shift == 7) + *dst = 0; + *dst |= ((source[i] != 0) << shift); + shift--; + if (shift < 0) { + shift = 7; + dst++; + } + } + } + break; + default: + _mesa_problem(ctx, "bad type in _mesa_pack_index_span"); + } + + free(stencil); +} + +#define DEPTH_VALUES(GLTYPE, GLTYPE2FLOAT) \ + do { \ + GLuint i; \ + const GLTYPE *src = (const GLTYPE *)source; \ + for (i = 0; i < n; i++) { \ + GLTYPE value = src[i]; \ + if (srcPacking->SwapBytes) { \ + if (sizeof(GLTYPE) == 2) { \ + SWAP2BYTE(value); \ + } else if (sizeof(GLTYPE) == 4) { \ + SWAP4BYTE(value); \ + } \ + } \ + depthValues[i] = GLTYPE2FLOAT(value); \ + } \ + } while (0) + + +/** + * Unpack a row of depth/z values from memory, returning GLushort, GLuint + * or GLfloat values. + * The glPixelTransfer (scale/bias) params will be applied. + * + * \param dstType one of GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, GL_FLOAT + * \param depthMax max value for returned GLushort or GLuint values + * (ignored for GLfloat). + */ +void +_mesa_unpack_depth_span( struct gl_context *ctx, GLuint n, + GLenum dstType, GLvoid *dest, GLuint depthMax, + GLenum srcType, const GLvoid *source, + const struct gl_pixelstore_attrib *srcPacking ) +{ + GLfloat *depthTemp, *depthValues; + GLboolean needClamp = GL_FALSE; + + /* Look for special cases first. + * Not only are these faster, they're less prone to numeric conversion + * problems. Otherwise, converting from an int type to a float then + * back to an int type can introduce errors that will show up as + * artifacts in things like depth peeling which uses glCopyTexImage. + */ + if (ctx->Pixel.DepthScale == 1.0 && ctx->Pixel.DepthBias == 0.0) { + if (srcType == GL_UNSIGNED_INT && dstType == GL_UNSIGNED_SHORT) { + const GLuint *src = (const GLuint *) source; + GLushort *dst = (GLushort *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = src[i] >> 16; + } + return; + } + if (srcType == GL_UNSIGNED_SHORT + && dstType == GL_UNSIGNED_INT + && depthMax == 0xffffffff) { + const GLushort *src = (const GLushort *) source; + GLuint *dst = (GLuint *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = src[i] | (src[i] << 16); + } + return; + } + if (srcType == GL_UNSIGNED_INT_24_8 + && dstType == GL_UNSIGNED_INT + && depthMax == 0xffffff) { + const GLuint *src = (const GLuint *) source; + GLuint *dst = (GLuint *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = src[i] >> 8; + } + return; + } + /* XXX may want to add additional cases here someday */ + } + + /* general case path follows */ + + depthTemp = (GLfloat *) malloc(n * sizeof(GLfloat)); + if (!depthTemp) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); + return; + } + + if (dstType == GL_FLOAT) { + depthValues = (GLfloat *) dest; + } + else { + depthValues = depthTemp; + } + + /* Convert incoming values to GLfloat. Some conversions will require + * clamping, below. + */ + switch (srcType) { + case GL_BYTE: + DEPTH_VALUES(GLbyte, BYTE_TO_FLOAT); + needClamp = GL_TRUE; + break; + case GL_UNSIGNED_BYTE: + DEPTH_VALUES(GLubyte, UBYTE_TO_FLOAT); + break; + case GL_SHORT: + DEPTH_VALUES(GLshort, SHORT_TO_FLOAT); + needClamp = GL_TRUE; + break; + case GL_UNSIGNED_SHORT: + DEPTH_VALUES(GLushort, USHORT_TO_FLOAT); + break; + case GL_INT: + DEPTH_VALUES(GLint, INT_TO_FLOAT); + needClamp = GL_TRUE; + break; + case GL_UNSIGNED_INT: + DEPTH_VALUES(GLuint, UINT_TO_FLOAT); + break; + case GL_UNSIGNED_INT_24_8_EXT: /* GL_EXT_packed_depth_stencil */ + if (dstType == GL_UNSIGNED_INT_24_8_EXT && + depthMax == 0xffffff && + ctx->Pixel.DepthScale == 1.0 && + ctx->Pixel.DepthBias == 0.0) { + const GLuint *src = (const GLuint *) source; + GLuint *zValues = (GLuint *) dest; + GLuint i; + for (i = 0; i < n; i++) { + GLuint value = src[i]; + if (srcPacking->SwapBytes) { + SWAP4BYTE(value); + } + zValues[i] = value & 0xffffff00; + } + return; + } + else { + const GLuint *src = (const GLuint *) source; + const GLfloat scale = 1.0f / 0xffffff; + GLuint i; + for (i = 0; i < n; i++) { + GLuint value = src[i]; + if (srcPacking->SwapBytes) { + SWAP4BYTE(value); + } + depthValues[i] = (value >> 8) * scale; + } + } + break; + case GL_FLOAT: + DEPTH_VALUES(GLfloat, 1*); + needClamp = GL_TRUE; + break; + case GL_HALF_FLOAT_ARB: + { + GLuint i; + const GLhalfARB *src = (const GLhalfARB *) source; + for (i = 0; i < n; i++) { + GLhalfARB value = src[i]; + if (srcPacking->SwapBytes) { + SWAP2BYTE(value); + } + depthValues[i] = _mesa_half_to_float(value); + } + needClamp = GL_TRUE; + } + break; + default: + _mesa_problem(NULL, "bad type in _mesa_unpack_depth_span()"); + free(depthTemp); + return; + } + + /* apply depth scale and bias */ + { + const GLfloat scale = ctx->Pixel.DepthScale; + const GLfloat bias = ctx->Pixel.DepthBias; + if (scale != 1.0 || bias != 0.0) { + GLuint i; + for (i = 0; i < n; i++) { + depthValues[i] = depthValues[i] * scale + bias; + } + needClamp = GL_TRUE; + } + } + + /* clamp to [0, 1] */ + if (needClamp) { + GLuint i; + for (i = 0; i < n; i++) { + depthValues[i] = (GLfloat)CLAMP(depthValues[i], 0.0, 1.0); + } + } + + /* + * Convert values to dstType + */ + if (dstType == GL_UNSIGNED_INT) { + GLuint *zValues = (GLuint *) dest; + GLuint i; + if (depthMax <= 0xffffff) { + /* no overflow worries */ + for (i = 0; i < n; i++) { + zValues[i] = (GLuint) (depthValues[i] * (GLfloat) depthMax); + } + } + else { + /* need to use double precision to prevent overflow problems */ + for (i = 0; i < n; i++) { + GLdouble z = depthValues[i] * (GLfloat) depthMax; + if (z >= (GLdouble) 0xffffffff) + zValues[i] = 0xffffffff; + else + zValues[i] = (GLuint) z; + } + } + } + else if (dstType == GL_UNSIGNED_SHORT) { + GLushort *zValues = (GLushort *) dest; + GLuint i; + ASSERT(depthMax <= 0xffff); + for (i = 0; i < n; i++) { + zValues[i] = (GLushort) (depthValues[i] * (GLfloat) depthMax); + } + } + else { + ASSERT(dstType == GL_FLOAT); + /*ASSERT(depthMax == 1.0F);*/ + } + + free(depthTemp); +} + + +/* + * Pack an array of depth values. The values are floats in [0,1]. + */ +void +_mesa_pack_depth_span( struct gl_context *ctx, GLuint n, GLvoid *dest, + GLenum dstType, const GLfloat *depthSpan, + const struct gl_pixelstore_attrib *dstPacking ) +{ + GLfloat *depthCopy = (GLfloat *) malloc(n * sizeof(GLfloat)); + if (!depthCopy) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel packing"); + return; + } + + if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0) { + memcpy(depthCopy, depthSpan, n * sizeof(GLfloat)); + _mesa_scale_and_bias_depth(ctx, n, depthCopy); + depthSpan = depthCopy; + } + + switch (dstType) { + case GL_UNSIGNED_BYTE: + { + GLubyte *dst = (GLubyte *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = FLOAT_TO_UBYTE( depthSpan[i] ); + } + } + break; + case GL_BYTE: + { + GLbyte *dst = (GLbyte *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = FLOAT_TO_BYTE( depthSpan[i] ); + } + } + break; + case GL_UNSIGNED_SHORT: + { + GLushort *dst = (GLushort *) dest; + GLuint i; + for (i = 0; i < n; i++) { + CLAMPED_FLOAT_TO_USHORT(dst[i], depthSpan[i]); + } + if (dstPacking->SwapBytes) { + _mesa_swap2( (GLushort *) dst, n ); + } + } + break; + case GL_SHORT: + { + GLshort *dst = (GLshort *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = FLOAT_TO_SHORT( depthSpan[i] ); + } + if (dstPacking->SwapBytes) { + _mesa_swap2( (GLushort *) dst, n ); + } + } + break; + case GL_UNSIGNED_INT: + { + GLuint *dst = (GLuint *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = FLOAT_TO_UINT( depthSpan[i] ); + } + if (dstPacking->SwapBytes) { + _mesa_swap4( (GLuint *) dst, n ); + } + } + break; + case GL_INT: + { + GLint *dst = (GLint *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = FLOAT_TO_INT( depthSpan[i] ); + } + if (dstPacking->SwapBytes) { + _mesa_swap4( (GLuint *) dst, n ); + } + } + break; + case GL_FLOAT: + { + GLfloat *dst = (GLfloat *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = depthSpan[i]; + } + if (dstPacking->SwapBytes) { + _mesa_swap4( (GLuint *) dst, n ); + } + } + break; + case GL_HALF_FLOAT_ARB: + { + GLhalfARB *dst = (GLhalfARB *) dest; + GLuint i; + for (i = 0; i < n; i++) { + dst[i] = _mesa_float_to_half(depthSpan[i]); + } + if (dstPacking->SwapBytes) { + _mesa_swap2( (GLushort *) dst, n ); + } + } + break; + default: + _mesa_problem(ctx, "bad type in _mesa_pack_depth_span"); + } + + free(depthCopy); +} + + + +/** + * Pack depth and stencil values as GL_DEPTH_STENCIL/GL_UNSIGNED_INT_24_8. + */ +void +_mesa_pack_depth_stencil_span(struct gl_context *ctx, GLuint n, GLuint *dest, + const GLfloat *depthVals, + const GLstencil *stencilVals, + const struct gl_pixelstore_attrib *dstPacking) +{ + GLfloat *depthCopy = (GLfloat *) malloc(n * sizeof(GLfloat)); + GLstencil *stencilCopy = (GLstencil *) malloc(n * sizeof(GLstencil)); + GLuint i; + + if (!depthCopy || !stencilCopy) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel packing"); + free(depthCopy); + free(stencilCopy); + return; + } + + if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0) { + memcpy(depthCopy, depthVals, n * sizeof(GLfloat)); + _mesa_scale_and_bias_depth(ctx, n, depthCopy); + depthVals = depthCopy; + } + + if (ctx->Pixel.IndexShift || + ctx->Pixel.IndexOffset || + ctx->Pixel.MapStencilFlag) { + memcpy(stencilCopy, stencilVals, n * sizeof(GLstencil)); + _mesa_apply_stencil_transfer_ops(ctx, n, stencilCopy); + stencilVals = stencilCopy; + } + + for (i = 0; i < n; i++) { + GLuint z = (GLuint) (depthVals[i] * 0xffffff); + dest[i] = (z << 8) | (stencilVals[i] & 0xff); + } + + if (dstPacking->SwapBytes) { + _mesa_swap4(dest, n); + } + + free(depthCopy); + free(stencilCopy); +} + + + + +/** + * Unpack image data. Apply byte swapping, byte flipping (bitmap). + * Return all image data in a contiguous block. This is used when we + * compile glDrawPixels, glTexImage, etc into a display list. We + * need a copy of the data in a standard format. + */ +void * +_mesa_unpack_image( GLuint dimensions, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *pixels, + const struct gl_pixelstore_attrib *unpack ) +{ + GLint bytesPerRow, compsPerRow; + GLboolean flipBytes, swap2, swap4; + + if (!pixels) + return NULL; /* not necessarily an error */ + + if (width <= 0 || height <= 0 || depth <= 0) + return NULL; /* generate error later */ + + if (type == GL_BITMAP) { + bytesPerRow = (width + 7) >> 3; + flipBytes = unpack->LsbFirst; + swap2 = swap4 = GL_FALSE; + compsPerRow = 0; + } + else { + const GLint bytesPerPixel = _mesa_bytes_per_pixel(format, type); + GLint components = _mesa_components_in_format(format); + GLint bytesPerComp; + + if (_mesa_type_is_packed(type)) + components = 1; + + if (bytesPerPixel <= 0 || components <= 0) + return NULL; /* bad format or type. generate error later */ + bytesPerRow = bytesPerPixel * width; + bytesPerComp = bytesPerPixel / components; + flipBytes = GL_FALSE; + swap2 = (bytesPerComp == 2) && unpack->SwapBytes; + swap4 = (bytesPerComp == 4) && unpack->SwapBytes; + compsPerRow = components * width; + assert(compsPerRow >= width); + } + + { + GLubyte *destBuffer + = (GLubyte *) malloc(bytesPerRow * height * depth); + GLubyte *dst; + GLint img, row; + if (!destBuffer) + return NULL; /* generate GL_OUT_OF_MEMORY later */ + + dst = destBuffer; + for (img = 0; img < depth; img++) { + for (row = 0; row < height; row++) { + const GLvoid *src = _mesa_image_address(dimensions, unpack, pixels, + width, height, format, type, img, row, 0); + + if ((type == GL_BITMAP) && (unpack->SkipPixels & 0x7)) { + GLint i; + flipBytes = GL_FALSE; + if (unpack->LsbFirst) { + GLubyte srcMask = 1 << (unpack->SkipPixels & 0x7); + GLubyte dstMask = 128; + const GLubyte *s = src; + GLubyte *d = dst; + *d = 0; + for (i = 0; i < width; i++) { + if (*s & srcMask) { + *d |= dstMask; + } + if (srcMask == 128) { + srcMask = 1; + s++; + } + else { + srcMask = srcMask << 1; + } + if (dstMask == 1) { + dstMask = 128; + d++; + *d = 0; + } + else { + dstMask = dstMask >> 1; + } + } + } + else { + GLubyte srcMask = 128 >> (unpack->SkipPixels & 0x7); + GLubyte dstMask = 128; + const GLubyte *s = src; + GLubyte *d = dst; + *d = 0; + for (i = 0; i < width; i++) { + if (*s & srcMask) { + *d |= dstMask; + } + if (srcMask == 1) { + srcMask = 128; + s++; + } + else { + srcMask = srcMask >> 1; + } + if (dstMask == 1) { + dstMask = 128; + d++; + *d = 0; + } + else { + dstMask = dstMask >> 1; + } + } + } + } + else { + memcpy(dst, src, bytesPerRow); + } + + /* byte flipping/swapping */ + if (flipBytes) { + flip_bytes((GLubyte *) dst, bytesPerRow); + } + else if (swap2) { + _mesa_swap2((GLushort*) dst, compsPerRow); + } + else if (swap4) { + _mesa_swap4((GLuint*) dst, compsPerRow); + } + dst += bytesPerRow; + } + } + return destBuffer; + } +} + diff --git a/mesalib/src/mesa/main/shaderapi.c b/mesalib/src/mesa/main/shaderapi.c index 066e8b427..514eed5d0 100644 --- a/mesalib/src/mesa/main/shaderapi.c +++ b/mesalib/src/mesa/main/shaderapi.c @@ -1,1946 +1,1938 @@ -/* - * Mesa 3-D graphics library - * - * Copyright (C) 2004-2008 Brian Paul All Rights Reserved. - * Copyright (C) 2009-2010 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file shaderapi.c - * \author Brian Paul - * - * Implementation of GLSL-related API functions. - * The glUniform* functions are in uniforms.c - * - * - * XXX things to do: - * 1. Check that the right error code is generated for all _mesa_error() calls. - * 2. Insert FLUSH_VERTICES calls in various places - */ - - -#include "main/glheader.h" -#include "main/context.h" -#include "main/dispatch.h" -#include "main/enums.h" -#include "main/hash.h" -#include "main/mfeatures.h" -#include "main/mtypes.h" -#include "main/shaderapi.h" -#include "main/shaderobj.h" -#include "program/program.h" -#include "program/prog_parameter.h" -#include "program/prog_uniform.h" -#include "ralloc.h" -#include -#include "../glsl/glsl_parser_extras.h" - -/** Define this to enable shader substitution (see below) */ -#define SHADER_SUBST 0 - - -/** - * Return mask of GLSL_x flags by examining the MESA_GLSL env var. - */ -static GLbitfield -get_shader_flags(void) -{ - GLbitfield flags = 0x0; - const char *env = _mesa_getenv("MESA_GLSL"); - - if (env) { - if (strstr(env, "dump")) - flags |= GLSL_DUMP; - if (strstr(env, "log")) - flags |= GLSL_LOG; - if (strstr(env, "nopvert")) - flags |= GLSL_NOP_VERT; - if (strstr(env, "nopfrag")) - flags |= GLSL_NOP_FRAG; - if (strstr(env, "nopt")) - flags |= GLSL_NO_OPT; - else if (strstr(env, "opt")) - flags |= GLSL_OPT; - if (strstr(env, "uniform")) - flags |= GLSL_UNIFORMS; - if (strstr(env, "useprog")) - flags |= GLSL_USE_PROG; - } - - return flags; -} - - -/** - * Initialize context's shader state. - */ -void -_mesa_init_shader_state(struct gl_context *ctx) -{ - /* Device drivers may override these to control what kind of instructions - * are generated by the GLSL compiler. - */ - struct gl_shader_compiler_options options; - gl_shader_type sh; - - memset(&options, 0, sizeof(options)); - options.MaxUnrollIterations = 32; - - /* Default pragma settings */ - options.DefaultPragmas.Optimize = GL_TRUE; - - for (sh = 0; sh < MESA_SHADER_TYPES; ++sh) - memcpy(&ctx->ShaderCompilerOptions[sh], &options, sizeof(options)); - - ctx->Shader.Flags = get_shader_flags(); -} - - -/** - * Free the per-context shader-related state. - */ -void -_mesa_free_shader_state(struct gl_context *ctx) -{ - _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentVertexProgram, NULL); - _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentGeometryProgram, - NULL); - _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentFragmentProgram, - NULL); - _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL); -} - - -/** - * Return the size of the given GLSL datatype, in floats (components). - */ -GLint -_mesa_sizeof_glsl_type(GLenum type) -{ - switch (type) { - case GL_FLOAT: - case GL_INT: - case GL_BOOL: - case GL_SAMPLER_1D: - case GL_SAMPLER_2D: - case GL_SAMPLER_3D: - case GL_SAMPLER_CUBE: - case GL_SAMPLER_1D_SHADOW: - case GL_SAMPLER_2D_SHADOW: - case GL_SAMPLER_2D_RECT_ARB: - case GL_SAMPLER_2D_RECT_SHADOW_ARB: - case GL_SAMPLER_1D_ARRAY_EXT: - case GL_SAMPLER_2D_ARRAY_EXT: - case GL_SAMPLER_1D_ARRAY_SHADOW_EXT: - case GL_SAMPLER_2D_ARRAY_SHADOW_EXT: - case GL_SAMPLER_CUBE_SHADOW_EXT: - return 1; - case GL_FLOAT_VEC2: - case GL_INT_VEC2: - case GL_UNSIGNED_INT_VEC2: - case GL_BOOL_VEC2: - return 2; - case GL_FLOAT_VEC3: - case GL_INT_VEC3: - case GL_UNSIGNED_INT_VEC3: - case GL_BOOL_VEC3: - return 3; - case GL_FLOAT_VEC4: - case GL_INT_VEC4: - case GL_UNSIGNED_INT_VEC4: - case GL_BOOL_VEC4: - return 4; - case GL_FLOAT_MAT2: - case GL_FLOAT_MAT2x3: - case GL_FLOAT_MAT2x4: - return 8; /* two float[4] vectors */ - case GL_FLOAT_MAT3: - case GL_FLOAT_MAT3x2: - case GL_FLOAT_MAT3x4: - return 12; /* three float[4] vectors */ - case GL_FLOAT_MAT4: - case GL_FLOAT_MAT4x2: - case GL_FLOAT_MAT4x3: - return 16; /* four float[4] vectors */ - default: - _mesa_problem(NULL, "Invalid type in _mesa_sizeof_glsl_type()"); - return 1; - } -} - - -/** - * Copy string from to , up to maxLength characters, returning - * length of in . - * \param src the strings source - * \param maxLength max chars to copy - * \param length returns number of chars copied - * \param dst the string destination - */ -void -_mesa_copy_string(GLchar *dst, GLsizei maxLength, - GLsizei *length, const GLchar *src) -{ - GLsizei len; - for (len = 0; len < maxLength - 1 && src && src[len]; len++) - dst[len] = src[len]; - if (maxLength > 0) - dst[len] = 0; - if (length) - *length = len; -} - - - -/** - * Confirm that the a shader type is valid and supported by the implementation - * - * \param ctx Current GL context - * \param type Shader target - * - */ -static bool -validate_shader_target(const struct gl_context *ctx, GLenum type) -{ - switch (type) { -#if FEATURE_ARB_fragment_shader - case GL_FRAGMENT_SHADER: - return ctx->Extensions.ARB_fragment_shader; -#endif -#if FEATURE_ARB_vertex_shader - case GL_VERTEX_SHADER: - return ctx->Extensions.ARB_vertex_shader; -#endif -#if FEATURE_ARB_geometry_shader4 - case GL_GEOMETRY_SHADER_ARB: - return ctx->Extensions.ARB_geometry_shader4; -#endif - default: - return false; - } -} - - -/** - * Find the length of the longest transform feedback varying name - * which was specified with glTransformFeedbackVaryings(). - */ -static GLint -longest_feedback_varying_name(const struct gl_shader_program *shProg) -{ - GLuint i; - GLint max = 0; - for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) { - GLint len = strlen(shProg->TransformFeedback.VaryingNames[i]); - if (len > max) - max = len; - } - return max; -} - - - -static GLboolean -is_program(struct gl_context *ctx, GLuint name) -{ - struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name); - return shProg ? GL_TRUE : GL_FALSE; -} - - -static GLboolean -is_shader(struct gl_context *ctx, GLuint name) -{ - struct gl_shader *shader = _mesa_lookup_shader(ctx, name); - return shader ? GL_TRUE : GL_FALSE; -} - - -/** - * Attach shader to a shader program. - */ -static void -attach_shader(struct gl_context *ctx, GLuint program, GLuint shader) -{ - struct gl_shader_program *shProg; - struct gl_shader *sh; - GLuint i, n; - - shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader"); - if (!shProg) - return; - - sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader"); - if (!sh) { - return; - } - - n = shProg->NumShaders; - for (i = 0; i < n; i++) { - if (shProg->Shaders[i] == sh) { - /* The shader is already attched to this program. The - * GL_ARB_shader_objects spec says: - * - * "The error INVALID_OPERATION is generated by AttachObjectARB - * if is already attached to ." - */ - _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader"); - return; - } - } - - /* grow list */ - shProg->Shaders = (struct gl_shader **) - _mesa_realloc(shProg->Shaders, - n * sizeof(struct gl_shader *), - (n + 1) * sizeof(struct gl_shader *)); - if (!shProg->Shaders) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader"); - return; - } - - /* append */ - shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */ - _mesa_reference_shader(ctx, &shProg->Shaders[n], sh); - shProg->NumShaders++; -} - - -static GLint -get_attrib_location(struct gl_context *ctx, GLuint program, const GLchar *name) -{ - struct gl_shader_program *shProg - = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation"); - - if (!shProg) { - return -1; - } - - if (!shProg->LinkStatus) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetAttribLocation(program not linked)"); - return -1; - } - - if (!name) - return -1; - - if (shProg->VertexProgram) { - const struct gl_program_parameter_list *attribs = - shProg->VertexProgram->Base.Attributes; - if (attribs) { - GLint i = _mesa_lookup_parameter_index(attribs, -1, name); - if (i >= 0) { - return attribs->Parameters[i].StateIndexes[0]; - } - } - } - return -1; -} - - -static void -bind_attrib_location(struct gl_context *ctx, GLuint program, GLuint index, - const GLchar *name) -{ - struct gl_shader_program *shProg; - const GLint size = -1; /* unknown size */ - GLint i, oldIndex; - GLenum datatype = GL_FLOAT_VEC4; - - shProg = _mesa_lookup_shader_program_err(ctx, program, - "glBindAttribLocation"); - if (!shProg) { - return; - } - - if (!name) - return; - - if (strncmp(name, "gl_", 3) == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBindAttribLocation(illegal name)"); - return; - } - - if (index >= ctx->Const.VertexProgram.MaxAttribs) { - _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)"); - return; - } - - if (shProg->LinkStatus) { - /* get current index/location for the attribute */ - oldIndex = get_attrib_location(ctx, program, name); - } - else { - oldIndex = -1; - } - - /* this will replace the current value if it's already in the list */ - i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index); - if (i < 0) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation"); - return; - } - - /* - * Note that this attribute binding won't go into effect until - * glLinkProgram is called again. - */ -} - - -static void -bind_frag_data_location(struct gl_context *ctx, GLuint program, - GLuint colorNumber, const GLchar *name) -{ - _mesa_problem(ctx, "bind_frag_data_location() not implemented yet"); -} - - -static GLuint -create_shader(struct gl_context *ctx, GLenum type) -{ - struct gl_shader *sh; - GLuint name; - - if (!validate_shader_target(ctx, type)) { - _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)"); - return 0; - } - - name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1); - sh = ctx->Driver.NewShader(ctx, name, type); - _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh); - - return name; -} - - -static GLuint -create_shader_program(struct gl_context *ctx) -{ - GLuint name; - struct gl_shader_program *shProg; - - name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1); - - shProg = ctx->Driver.NewShaderProgram(ctx, name); - - _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg); - - assert(shProg->RefCount == 1); - - return name; -} - - -/** - * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's - * DeleteProgramARB. - */ -static void -delete_shader_program(struct gl_context *ctx, GLuint name) -{ - /* - * NOTE: deleting shaders/programs works a bit differently than - * texture objects (and buffer objects, etc). Shader/program - * handles/IDs exist in the hash table until the object is really - * deleted (refcount==0). With texture objects, the handle/ID is - * removed from the hash table in glDeleteTextures() while the tex - * object itself might linger until its refcount goes to zero. - */ - struct gl_shader_program *shProg; - - shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram"); - if (!shProg) - return; - - shProg->DeletePending = GL_TRUE; - - /* effectively, decr shProg's refcount */ - _mesa_reference_shader_program(ctx, &shProg, NULL); -} - - -static void -delete_shader(struct gl_context *ctx, GLuint shader) -{ - struct gl_shader *sh; - - sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader"); - if (!sh) - return; - - sh->DeletePending = GL_TRUE; - - /* effectively, decr sh's refcount */ - _mesa_reference_shader(ctx, &sh, NULL); -} - - -static void -detach_shader(struct gl_context *ctx, GLuint program, GLuint shader) -{ - struct gl_shader_program *shProg; - GLuint n; - GLuint i, j; - - shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader"); - if (!shProg) - return; - - n = shProg->NumShaders; - - for (i = 0; i < n; i++) { - if (shProg->Shaders[i]->Name == shader) { - /* found it */ - struct gl_shader **newList; - - /* release */ - _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL); - - /* alloc new, smaller array */ - newList = (struct gl_shader **) - malloc((n - 1) * sizeof(struct gl_shader *)); - if (!newList) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader"); - return; - } - for (j = 0; j < i; j++) { - newList[j] = shProg->Shaders[j]; - } - while (++i < n) - newList[j++] = shProg->Shaders[i]; - free(shProg->Shaders); - - shProg->Shaders = newList; - shProg->NumShaders = n - 1; - -#ifdef DEBUG - /* sanity check */ - { - for (j = 0; j < shProg->NumShaders; j++) { - assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER || - shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER); - assert(shProg->Shaders[j]->RefCount > 0); - } - } -#endif - - return; - } - } - - /* not found */ - { - GLenum err; - if (is_shader(ctx, shader)) - err = GL_INVALID_OPERATION; - else if (is_program(ctx, shader)) - err = GL_INVALID_OPERATION; - else - err = GL_INVALID_VALUE; - _mesa_error(ctx, err, "glDetachProgram(shader)"); - return; - } -} - - -static void -get_active_attrib(struct gl_context *ctx, GLuint program, GLuint index, - GLsizei maxLength, GLsizei *length, GLint *size, - GLenum *type, GLchar *nameOut) -{ - const struct gl_program_parameter_list *attribs = NULL; - struct gl_shader_program *shProg; - - shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib"); - if (!shProg) - return; - - if (shProg->VertexProgram) - attribs = shProg->VertexProgram->Base.Attributes; - - if (!attribs || index >= attribs->NumParameters) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)"); - return; - } - - _mesa_copy_string(nameOut, maxLength, length, - attribs->Parameters[index].Name); - - if (size) - *size = attribs->Parameters[index].Size - / _mesa_sizeof_glsl_type(attribs->Parameters[index].DataType); - - if (type) - *type = attribs->Parameters[index].DataType; -} - - -/** - * Return list of shaders attached to shader program. - */ -static void -get_attached_shaders(struct gl_context *ctx, GLuint program, GLsizei maxCount, - GLsizei *count, GLuint *obj) -{ - struct gl_shader_program *shProg = - _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders"); - if (shProg) { - GLuint i; - for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) { - obj[i] = shProg->Shaders[i]->Name; - } - if (count) - *count = i; - } -} - - -static GLint -get_frag_data_location(struct gl_context *ctx, GLuint program, - const GLchar *name) -{ - _mesa_problem(ctx, "get_frag_data_location() not implemented yet"); - return -1; -} - - - -/** - * glGetHandleARB() - return ID/name of currently bound shader program. - */ -static GLuint -get_handle(struct gl_context *ctx, GLenum pname) -{ - if (pname == GL_PROGRAM_OBJECT_ARB) { - if (ctx->Shader.ActiveProgram) - return ctx->Shader.ActiveProgram->Name; - else - return 0; - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB"); - return 0; - } -} - - -/** - * glGetProgramiv() - get shader program state. - * Note that this is for GLSL shader programs, not ARB vertex/fragment - * programs (see glGetProgramivARB). - */ -static void -get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *params) -{ - const struct gl_program_parameter_list *attribs; - struct gl_shader_program *shProg - = _mesa_lookup_shader_program(ctx, program); - - if (!shProg) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)"); - return; - } - - if (shProg->VertexProgram) - attribs = shProg->VertexProgram->Base.Attributes; - else - attribs = NULL; - - switch (pname) { - case GL_DELETE_STATUS: - *params = shProg->DeletePending; - break; - case GL_LINK_STATUS: - *params = shProg->LinkStatus; - break; - case GL_VALIDATE_STATUS: - *params = shProg->Validated; - break; - case GL_INFO_LOG_LENGTH: - *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0; - break; - case GL_ATTACHED_SHADERS: - *params = shProg->NumShaders; - break; - case GL_ACTIVE_ATTRIBUTES: - *params = attribs ? attribs->NumParameters : 0; - break; - case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: - *params = _mesa_longest_parameter_name(attribs, PROGRAM_INPUT) + 1; - break; - case GL_ACTIVE_UNIFORMS: - *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0; - break; - case GL_ACTIVE_UNIFORM_MAX_LENGTH: - *params = _mesa_longest_uniform_name(shProg->Uniforms); - if (*params > 0) - (*params)++; /* add one for terminating zero */ - break; - case GL_PROGRAM_BINARY_LENGTH_OES: - *params = 0; - break; -#if FEATURE_EXT_transform_feedback - case GL_TRANSFORM_FEEDBACK_VARYINGS: - *params = shProg->TransformFeedback.NumVarying; - break; - case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: - *params = longest_feedback_varying_name(shProg) + 1; - break; - case GL_TRANSFORM_FEEDBACK_BUFFER_MODE: - *params = shProg->TransformFeedback.BufferMode; - break; -#endif -#if FEATURE_ARB_geometry_shader4 - case GL_GEOMETRY_VERTICES_OUT_ARB: - *params = shProg->Geom.VerticesOut; - break; - case GL_GEOMETRY_INPUT_TYPE_ARB: - *params = shProg->Geom.InputType; - break; - case GL_GEOMETRY_OUTPUT_TYPE_ARB: - *params = shProg->Geom.OutputType; - break; -#endif - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)"); - return; - } -} - - -/** - * glGetShaderiv() - get GLSL shader state - */ -static void -get_shaderiv(struct gl_context *ctx, GLuint name, GLenum pname, GLint *params) -{ - struct gl_shader *shader = - _mesa_lookup_shader_err(ctx, name, "glGetShaderiv"); - - if (!shader) { - return; - } - - switch (pname) { - case GL_SHADER_TYPE: - *params = shader->Type; - break; - case GL_DELETE_STATUS: - *params = shader->DeletePending; - break; - case GL_COMPILE_STATUS: - *params = shader->CompileStatus; - break; - case GL_INFO_LOG_LENGTH: - *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0; - break; - case GL_SHADER_SOURCE_LENGTH: - *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)"); - return; - } -} - - -static void -get_program_info_log(struct gl_context *ctx, GLuint program, GLsizei bufSize, - GLsizei *length, GLchar *infoLog) -{ - struct gl_shader_program *shProg - = _mesa_lookup_shader_program(ctx, program); - if (!shProg) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)"); - return; - } - _mesa_copy_string(infoLog, bufSize, length, shProg->InfoLog); -} - - -static void -get_shader_info_log(struct gl_context *ctx, GLuint shader, GLsizei bufSize, - GLsizei *length, GLchar *infoLog) -{ - struct gl_shader *sh = _mesa_lookup_shader(ctx, shader); - if (!sh) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)"); - return; - } - _mesa_copy_string(infoLog, bufSize, length, sh->InfoLog); -} - - -/** - * Return shader source code. - */ -static void -get_shader_source(struct gl_context *ctx, GLuint shader, GLsizei maxLength, - GLsizei *length, GLchar *sourceOut) -{ - struct gl_shader *sh; - sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource"); - if (!sh) { - return; - } - _mesa_copy_string(sourceOut, maxLength, length, sh->Source); -} - - -/** - * Set/replace shader source code. - */ -static void -shader_source(struct gl_context *ctx, GLuint shader, const GLchar *source) -{ - struct gl_shader *sh; - - sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource"); - if (!sh) - return; - - /* free old shader source string and install new one */ - if (sh->Source) { - free((void *) sh->Source); - } - sh->Source = source; - sh->CompileStatus = GL_FALSE; -#ifdef DEBUG - sh->SourceChecksum = _mesa_str_checksum(sh->Source); -#endif -} - - -/** - * Compile a shader. - */ -static void -compile_shader(struct gl_context *ctx, GLuint shaderObj) -{ - struct gl_shader *sh; - struct gl_shader_compiler_options *options; - - sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader"); - if (!sh) - return; - - options = &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(sh->Type)]; - - /* set default pragma state for shader */ - sh->Pragmas = options->DefaultPragmas; - - /* this call will set the sh->CompileStatus field to indicate if - * compilation was successful. - */ - _mesa_glsl_compile_shader(ctx, sh); -} - - -/** - * Link a program's shaders. - */ -static void -link_program(struct gl_context *ctx, GLuint program) -{ - struct gl_shader_program *shProg; - struct gl_transform_feedback_object *obj = - ctx->TransformFeedback.CurrentObject; - - shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram"); - if (!shProg) - return; - - if (obj->Active - && (shProg == ctx->Shader.CurrentVertexProgram - || shProg == ctx->Shader.CurrentGeometryProgram - || shProg == ctx->Shader.CurrentFragmentProgram)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glLinkProgram(transform feedback active"); - return; - } - - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - - _mesa_glsl_link_shader(ctx, shProg); - - /* debug code */ - if (0) { - GLuint i; - - printf("Link %u shaders in program %u: %s\n", - shProg->NumShaders, shProg->Name, - shProg->LinkStatus ? "Success" : "Failed"); - - for (i = 0; i < shProg->NumShaders; i++) { - printf(" shader %u, type 0x%x\n", - shProg->Shaders[i]->Name, - shProg->Shaders[i]->Type); - } - } -} - - -/** - * Print basic shader info (for debug). - */ -static void -print_shader_info(const struct gl_shader_program *shProg) -{ - GLuint i; - - printf("Mesa: glUseProgram(%u)\n", shProg->Name); - for (i = 0; i < shProg->NumShaders; i++) { - const char *s; - switch (shProg->Shaders[i]->Type) { - case GL_VERTEX_SHADER: - s = "vertex"; - break; - case GL_FRAGMENT_SHADER: - s = "fragment"; - break; - case GL_GEOMETRY_SHADER: - s = "geometry"; - break; - default: - s = ""; - } - printf(" %s shader %u, checksum %u\n", s, - shProg->Shaders[i]->Name, - shProg->Shaders[i]->SourceChecksum); - } - if (shProg->VertexProgram) - printf(" vert prog %u\n", shProg->VertexProgram->Base.Id); - if (shProg->FragmentProgram) - printf(" frag prog %u\n", shProg->FragmentProgram->Base.Id); -} - - -/** - * Use the named shader program for subsequent glUniform calls - */ -void -_mesa_active_program(struct gl_context *ctx, struct gl_shader_program *shProg, - const char *caller) -{ - if ((shProg != NULL) && !shProg->LinkStatus) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(program %u not linked)", caller, shProg->Name); - return; - } - - if (ctx->Shader.ActiveProgram != shProg) { - _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, shProg); - } -} - -/** - */ -static bool -use_shader_program(struct gl_context *ctx, GLenum type, - struct gl_shader_program *shProg) -{ - struct gl_shader_program **target; - - switch (type) { -#if FEATURE_ARB_vertex_shader - case GL_VERTEX_SHADER: - target = &ctx->Shader.CurrentVertexProgram; - if ((shProg == NULL) - || (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)) { - shProg = NULL; - } - break; -#endif -#if FEATURE_ARB_geometry_shader4 - case GL_GEOMETRY_SHADER_ARB: - target = &ctx->Shader.CurrentGeometryProgram; - if ((shProg == NULL) - || (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY] == NULL)) { - shProg = NULL; - } - break; -#endif -#if FEATURE_ARB_fragment_shader - case GL_FRAGMENT_SHADER: - target = &ctx->Shader.CurrentFragmentProgram; - if ((shProg == NULL) - || (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)) { - shProg = NULL; - } - break; -#endif - default: - return false; - } - - if (*target != shProg) { - FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); - _mesa_reference_shader_program(ctx, target, shProg); - return true; - } - - return false; -} - -/** - * Use the named shader program for subsequent rendering. - */ -void -_mesa_use_program(struct gl_context *ctx, struct gl_shader_program *shProg) -{ - use_shader_program(ctx, GL_VERTEX_SHADER, shProg); - use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB, shProg); - use_shader_program(ctx, GL_FRAGMENT_SHADER, shProg); - _mesa_active_program(ctx, shProg, "glUseProgram"); - - if (ctx->Driver.UseProgram) - ctx->Driver.UseProgram(ctx, shProg); -} - - -/** - * Validate a program's samplers. - * Specifically, check that there aren't two samplers of different types - * pointing to the same texture unit. - * \return GL_TRUE if valid, GL_FALSE if invalid - */ -static GLboolean -validate_samplers(const struct gl_program *prog, char *errMsg) -{ - static const char *targetName[] = { - "TEXTURE_BUFFER", - "TEXTURE_2D_ARRAY", - "TEXTURE_1D_ARRAY", - "TEXTURE_CUBE", - "TEXTURE_3D", - "TEXTURE_RECT", - "TEXTURE_2D", - "TEXTURE_1D", - }; - GLint targetUsed[MAX_TEXTURE_IMAGE_UNITS]; - GLbitfield samplersUsed = prog->SamplersUsed; - GLuint i; - - assert(Elements(targetName) == NUM_TEXTURE_TARGETS); - - if (samplersUsed == 0x0) - return GL_TRUE; - - for (i = 0; i < Elements(targetUsed); i++) - targetUsed[i] = -1; - - /* walk over bits which are set in 'samplers' */ - while (samplersUsed) { - GLuint unit; - gl_texture_index target; - GLint sampler = _mesa_ffs(samplersUsed) - 1; - assert(sampler >= 0); - assert(sampler < MAX_TEXTURE_IMAGE_UNITS); - unit = prog->SamplerUnits[sampler]; - target = prog->SamplerTargets[sampler]; - if (targetUsed[unit] != -1 && targetUsed[unit] != (int) target) { - _mesa_snprintf(errMsg, 100, - "Texture unit %d is accessed both as %s and %s", - unit, targetName[targetUsed[unit]], targetName[target]); - return GL_FALSE; - } - targetUsed[unit] = target; - samplersUsed ^= (1 << sampler); - } - - return GL_TRUE; -} - - -/** - * Do validation of the given shader program. - * \param errMsg returns error message if validation fails. - * \return GL_TRUE if valid, GL_FALSE if invalid (and set errMsg) - */ -static GLboolean -validate_shader_program(const struct gl_shader_program *shProg, - char *errMsg) -{ - const struct gl_vertex_program *vp = shProg->VertexProgram; - const struct gl_fragment_program *fp = shProg->FragmentProgram; - - if (!shProg->LinkStatus) { - return GL_FALSE; - } - - /* From the GL spec, a program is invalid if any of these are true: - - any two active samplers in the current program object are of - different types, but refer to the same texture image unit, - - any active sampler in the current program object refers to a texture - image unit where fixed-function fragment processing accesses a - texture target that does not match the sampler type, or - - the sum of the number of active samplers in the program and the - number of texture image units enabled for fixed-function fragment - processing exceeds the combined limit on the total number of texture - image units allowed. - */ - - - /* - * Check: any two active samplers in the current program object are of - * different types, but refer to the same texture image unit, - */ - if (vp && !validate_samplers(&vp->Base, errMsg)) { - return GL_FALSE; - } - if (fp && !validate_samplers(&fp->Base, errMsg)) { - return GL_FALSE; - } - - return GL_TRUE; -} - - -/** - * Called via glValidateProgram() - */ -static void -validate_program(struct gl_context *ctx, GLuint program) -{ - struct gl_shader_program *shProg; - char errMsg[100]; - - shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram"); - if (!shProg) { - return; - } - - shProg->Validated = validate_shader_program(shProg, errMsg); - if (!shProg->Validated) { - /* update info log */ - if (shProg->InfoLog) { - ralloc_free(shProg->InfoLog); - } - shProg->InfoLog = ralloc_strdup(shProg, errMsg); - } -} - - - -void GLAPIENTRY -_mesa_AttachObjectARB(GLhandleARB program, GLhandleARB shader) -{ - GET_CURRENT_CONTEXT(ctx); - attach_shader(ctx, program, shader); -} - - -void GLAPIENTRY -_mesa_AttachShader(GLuint program, GLuint shader) -{ - GET_CURRENT_CONTEXT(ctx); - attach_shader(ctx, program, shader); -} - - -void GLAPIENTRY -_mesa_BindAttribLocationARB(GLhandleARB program, GLuint index, - const GLcharARB *name) -{ - GET_CURRENT_CONTEXT(ctx); - bind_attrib_location(ctx, program, index, name); -} - - -/* GL_EXT_gpu_shader4, GL3 */ -void GLAPIENTRY -_mesa_BindFragDataLocation(GLuint program, GLuint colorNumber, - const GLchar *name) -{ - GET_CURRENT_CONTEXT(ctx); - bind_frag_data_location(ctx, program, colorNumber, name); -} - - -void GLAPIENTRY -_mesa_CompileShaderARB(GLhandleARB shaderObj) -{ - GET_CURRENT_CONTEXT(ctx); - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glCompileShader %u\n", shaderObj); - compile_shader(ctx, shaderObj); -} - - -GLuint GLAPIENTRY -_mesa_CreateShader(GLenum type) -{ - GET_CURRENT_CONTEXT(ctx); - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glCreateShader %s\n", _mesa_lookup_enum_by_nr(type)); - return create_shader(ctx, type); -} - - -GLhandleARB GLAPIENTRY -_mesa_CreateShaderObjectARB(GLenum type) -{ - GET_CURRENT_CONTEXT(ctx); - return create_shader(ctx, type); -} - - -GLuint GLAPIENTRY -_mesa_CreateProgram(void) -{ - GET_CURRENT_CONTEXT(ctx); - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glCreateProgram\n"); - return create_shader_program(ctx); -} - - -GLhandleARB GLAPIENTRY -_mesa_CreateProgramObjectARB(void) -{ - GET_CURRENT_CONTEXT(ctx); - return create_shader_program(ctx); -} - - -void GLAPIENTRY -_mesa_DeleteObjectARB(GLhandleARB obj) -{ - if (MESA_VERBOSE & VERBOSE_API) { - GET_CURRENT_CONTEXT(ctx); - _mesa_debug(ctx, "glDeleteObjectARB(%u)\n", obj); - } - - if (obj) { - GET_CURRENT_CONTEXT(ctx); - FLUSH_VERTICES(ctx, 0); - if (is_program(ctx, obj)) { - delete_shader_program(ctx, obj); - } - else if (is_shader(ctx, obj)) { - delete_shader(ctx, obj); - } - else { - /* error? */ - } - } -} - - -void GLAPIENTRY -_mesa_DeleteProgram(GLuint name) -{ - if (name) { - GET_CURRENT_CONTEXT(ctx); - FLUSH_VERTICES(ctx, 0); - delete_shader_program(ctx, name); - } -} - - -void GLAPIENTRY -_mesa_DeleteShader(GLuint name) -{ - if (name) { - GET_CURRENT_CONTEXT(ctx); - FLUSH_VERTICES(ctx, 0); - delete_shader(ctx, name); - } -} - - -void GLAPIENTRY -_mesa_DetachObjectARB(GLhandleARB program, GLhandleARB shader) -{ - GET_CURRENT_CONTEXT(ctx); - detach_shader(ctx, program, shader); -} - - -void GLAPIENTRY -_mesa_DetachShader(GLuint program, GLuint shader) -{ - GET_CURRENT_CONTEXT(ctx); - detach_shader(ctx, program, shader); -} - - -void GLAPIENTRY -_mesa_GetActiveAttribARB(GLhandleARB program, GLuint index, - GLsizei maxLength, GLsizei * length, GLint * size, - GLenum * type, GLcharARB * name) -{ - GET_CURRENT_CONTEXT(ctx); - get_active_attrib(ctx, program, index, maxLength, length, size, type, name); -} - - -void GLAPIENTRY -_mesa_GetAttachedObjectsARB(GLhandleARB container, GLsizei maxCount, - GLsizei * count, GLhandleARB * obj) -{ - GET_CURRENT_CONTEXT(ctx); - get_attached_shaders(ctx, container, maxCount, count, obj); -} - - -void GLAPIENTRY -_mesa_GetAttachedShaders(GLuint program, GLsizei maxCount, - GLsizei *count, GLuint *obj) -{ - GET_CURRENT_CONTEXT(ctx); - get_attached_shaders(ctx, program, maxCount, count, obj); -} - - -GLint GLAPIENTRY -_mesa_GetAttribLocationARB(GLhandleARB program, const GLcharARB * name) -{ - GET_CURRENT_CONTEXT(ctx); - return get_attrib_location(ctx, program, name); -} - - -/* GL_EXT_gpu_shader4, GL3 */ -GLint GLAPIENTRY -_mesa_GetFragDataLocation(GLuint program, const GLchar *name) -{ - GET_CURRENT_CONTEXT(ctx); - return get_frag_data_location(ctx, program, name); -} - - - -void GLAPIENTRY -_mesa_GetInfoLogARB(GLhandleARB object, GLsizei maxLength, GLsizei * length, - GLcharARB * infoLog) -{ - GET_CURRENT_CONTEXT(ctx); - if (is_program(ctx, object)) { - get_program_info_log(ctx, object, maxLength, length, infoLog); - } - else if (is_shader(ctx, object)) { - get_shader_info_log(ctx, object, maxLength, length, infoLog); - } - else { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetInfoLogARB"); - } -} - - -void GLAPIENTRY -_mesa_GetObjectParameterivARB(GLhandleARB object, GLenum pname, GLint *params) -{ - GET_CURRENT_CONTEXT(ctx); - /* Implement in terms of GetProgramiv, GetShaderiv */ - if (is_program(ctx, object)) { - if (pname == GL_OBJECT_TYPE_ARB) { - *params = GL_PROGRAM_OBJECT_ARB; - } - else { - get_programiv(ctx, object, pname, params); - } - } - else if (is_shader(ctx, object)) { - if (pname == GL_OBJECT_TYPE_ARB) { - *params = GL_SHADER_OBJECT_ARB; - } - else { - get_shaderiv(ctx, object, pname, params); - } - } - else { - _mesa_error(ctx, GL_INVALID_VALUE, "glGetObjectParameterivARB"); - } -} - - -void GLAPIENTRY -_mesa_GetObjectParameterfvARB(GLhandleARB object, GLenum pname, - GLfloat *params) -{ - GLint iparams[1]; /* XXX is one element enough? */ - _mesa_GetObjectParameterivARB(object, pname, iparams); - params[0] = (GLfloat) iparams[0]; -} - - -void GLAPIENTRY -_mesa_GetProgramiv(GLuint program, GLenum pname, GLint *params) -{ - GET_CURRENT_CONTEXT(ctx); - get_programiv(ctx, program, pname, params); -} - - -void GLAPIENTRY -_mesa_GetShaderiv(GLuint shader, GLenum pname, GLint *params) -{ - GET_CURRENT_CONTEXT(ctx); - get_shaderiv(ctx, shader, pname, params); -} - - -void GLAPIENTRY -_mesa_GetProgramInfoLog(GLuint program, GLsizei bufSize, - GLsizei *length, GLchar *infoLog) -{ - GET_CURRENT_CONTEXT(ctx); - get_program_info_log(ctx, program, bufSize, length, infoLog); -} - - -void GLAPIENTRY -_mesa_GetShaderInfoLog(GLuint shader, GLsizei bufSize, - GLsizei *length, GLchar *infoLog) -{ - GET_CURRENT_CONTEXT(ctx); - get_shader_info_log(ctx, shader, bufSize, length, infoLog); -} - - -void GLAPIENTRY -_mesa_GetShaderSourceARB(GLhandleARB shader, GLsizei maxLength, - GLsizei *length, GLcharARB *sourceOut) -{ - GET_CURRENT_CONTEXT(ctx); - get_shader_source(ctx, shader, maxLength, length, sourceOut); -} - - -GLhandleARB GLAPIENTRY -_mesa_GetHandleARB(GLenum pname) -{ - GET_CURRENT_CONTEXT(ctx); - return get_handle(ctx, pname); -} - - -GLboolean GLAPIENTRY -_mesa_IsProgram(GLuint name) -{ - GET_CURRENT_CONTEXT(ctx); - return is_program(ctx, name); -} - - -GLboolean GLAPIENTRY -_mesa_IsShader(GLuint name) -{ - GET_CURRENT_CONTEXT(ctx); - return is_shader(ctx, name); -} - - -void GLAPIENTRY -_mesa_LinkProgramARB(GLhandleARB programObj) -{ - GET_CURRENT_CONTEXT(ctx); - link_program(ctx, programObj); -} - - - -/** - * Read shader source code from a file. - * Useful for debugging to override an app's shader. - */ -static GLcharARB * -read_shader(const char *fname) -{ - const int max = 50*1000; - FILE *f = fopen(fname, "r"); - GLcharARB *buffer, *shader; - int len; - - if (!f) { - return NULL; - } - - buffer = (char *) malloc(max); - len = fread(buffer, 1, max, f); - buffer[len] = 0; - - fclose(f); - - shader = _mesa_strdup(buffer); - free(buffer); - - return shader; -} - - -/** - * Called via glShaderSource() and glShaderSourceARB() API functions. - * Basically, concatenate the source code strings into one long string - * and pass it to _mesa_shader_source(). - */ -void GLAPIENTRY -_mesa_ShaderSourceARB(GLhandleARB shaderObj, GLsizei count, - const GLcharARB ** string, const GLint * length) -{ - GET_CURRENT_CONTEXT(ctx); - GLint *offsets; - GLsizei i, totalLength; - GLcharARB *source; - GLuint checksum; - - if (!shaderObj || string == NULL) { - _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB"); - return; - } - - /* - * This array holds offsets of where the appropriate string ends, thus the - * last element will be set to the total length of the source code. - */ - offsets = (GLint *) malloc(count * sizeof(GLint)); - if (offsets == NULL) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB"); - return; - } - - for (i = 0; i < count; i++) { - if (string[i] == NULL) { - free((GLvoid *) offsets); - _mesa_error(ctx, GL_INVALID_OPERATION, "glShaderSourceARB(null string)"); - return; - } - if (length == NULL || length[i] < 0) - offsets[i] = strlen(string[i]); - else - offsets[i] = length[i]; - /* accumulate string lengths */ - if (i > 0) - offsets[i] += offsets[i - 1]; - } - - /* Total length of source string is sum off all strings plus two. - * One extra byte for terminating zero, another extra byte to silence - * valgrind warnings in the parser/grammer code. - */ - totalLength = offsets[count - 1] + 2; - source = (GLcharARB *) malloc(totalLength * sizeof(GLcharARB)); - if (source == NULL) { - free((GLvoid *) offsets); - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB"); - return; - } - - for (i = 0; i < count; i++) { - GLint start = (i > 0) ? offsets[i - 1] : 0; - memcpy(source + start, string[i], - (offsets[i] - start) * sizeof(GLcharARB)); - } - source[totalLength - 1] = '\0'; - source[totalLength - 2] = '\0'; - - if (SHADER_SUBST) { - /* Compute the shader's source code checksum then try to open a file - * named newshader_. If it exists, use it in place of the - * original shader source code. For debugging. - */ - char filename[100]; - GLcharARB *newSource; - - checksum = _mesa_str_checksum(source); - - _mesa_snprintf(filename, sizeof(filename), "newshader_%d", checksum); - - newSource = read_shader(filename); - if (newSource) { - fprintf(stderr, "Mesa: Replacing shader %u chksum=%d with %s\n", - shaderObj, checksum, filename); - free(source); - source = newSource; - } - } - - shader_source(ctx, shaderObj, source); - - if (SHADER_SUBST) { - struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj); - if (sh) - sh->SourceChecksum = checksum; /* save original checksum */ - } - - free(offsets); -} - - -void GLAPIENTRY -_mesa_UseProgramObjectARB(GLhandleARB program) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_shader_program *shProg; - struct gl_transform_feedback_object *obj = - ctx->TransformFeedback.CurrentObject; - - if (obj->Active) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glUseProgram(transform feedback active)"); - return; - } - - if (program) { - shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram"); - if (!shProg) { - return; - } - if (!shProg->LinkStatus) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glUseProgram(program %u not linked)", program); - return; - } - - /* debug code */ - if (ctx->Shader.Flags & GLSL_USE_PROG) { - print_shader_info(shProg); - } - } - else { - shProg = NULL; - } - - _mesa_use_program(ctx, shProg); -} - - -void GLAPIENTRY -_mesa_ValidateProgramARB(GLhandleARB program) -{ - GET_CURRENT_CONTEXT(ctx); - validate_program(ctx, program); -} - -#ifdef FEATURE_ES2 - -void GLAPIENTRY -_mesa_GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, - GLint* range, GLint* precision) -{ - const struct gl_program_constants *limits; - const struct gl_precision *p; - GET_CURRENT_CONTEXT(ctx); - - switch (shadertype) { - case GL_VERTEX_SHADER: - limits = &ctx->Const.VertexProgram; - break; - case GL_FRAGMENT_SHADER: - limits = &ctx->Const.FragmentProgram; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetShaderPrecisionFormat(shadertype)"); - return; - } - - switch (precisiontype) { - case GL_LOW_FLOAT: - p = &limits->LowFloat; - break; - case GL_MEDIUM_FLOAT: - p = &limits->MediumFloat; - break; - case GL_HIGH_FLOAT: - p = &limits->HighFloat; - break; - case GL_LOW_INT: - p = &limits->LowInt; - break; - case GL_MEDIUM_INT: - p = &limits->MediumInt; - break; - case GL_HIGH_INT: - p = &limits->HighInt; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetShaderPrecisionFormat(precisiontype)"); - return; - } - - range[0] = p->RangeMin; - range[1] = p->RangeMax; - precision[0] = p->Precision; -} - - -void GLAPIENTRY -_mesa_ReleaseShaderCompiler(void) -{ - _mesa_destroy_shader_compiler_caches(); -} - - -void GLAPIENTRY -_mesa_ShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, - const void* binary, GLint length) -{ - GET_CURRENT_CONTEXT(ctx); - (void) n; - (void) shaders; - (void) binaryformat; - (void) binary; - (void) length; - _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__); -} - -#endif /* FEATURE_ES2 */ - - -#if FEATURE_ARB_geometry_shader4 - -void GLAPIENTRY -_mesa_ProgramParameteriARB(GLuint program, GLenum pname, - GLint value) -{ - struct gl_shader_program *shProg; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - shProg = _mesa_lookup_shader_program_err(ctx, program, - "glProgramParameteri"); - if (!shProg) - return; - - switch (pname) { - case GL_GEOMETRY_VERTICES_OUT_ARB: - if (value < 1 || - (unsigned) value > ctx->Const.MaxGeometryOutputVertices) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glProgramParameteri(GL_GEOMETRY_VERTICES_OUT_ARB=%d", - value); - return; - } - shProg->Geom.VerticesOut = value; - break; - case GL_GEOMETRY_INPUT_TYPE_ARB: - switch (value) { - case GL_POINTS: - case GL_LINES: - case GL_LINES_ADJACENCY_ARB: - case GL_TRIANGLES: - case GL_TRIANGLES_ADJACENCY_ARB: - shProg->Geom.InputType = value; - break; - default: - _mesa_error(ctx, GL_INVALID_VALUE, - "glProgramParameteri(geometry input type = %s", - _mesa_lookup_enum_by_nr(value)); - return; - } - break; - case GL_GEOMETRY_OUTPUT_TYPE_ARB: - switch (value) { - case GL_POINTS: - case GL_LINE_STRIP: - case GL_TRIANGLE_STRIP: - shProg->Geom.OutputType = value; - break; - default: - _mesa_error(ctx, GL_INVALID_VALUE, - "glProgramParameteri(geometry output type = %s", - _mesa_lookup_enum_by_nr(value)); - return; - } - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameteriARB(pname=%s)", - _mesa_lookup_enum_by_nr(pname)); - break; - } -} - -#endif - -void -_mesa_use_shader_program(struct gl_context *ctx, GLenum type, - struct gl_shader_program *shProg) -{ - use_shader_program(ctx, type, shProg); - - if (ctx->Driver.UseProgram) - ctx->Driver.UseProgram(ctx, shProg); -} - -void GLAPIENTRY -_mesa_UseShaderProgramEXT(GLenum type, GLuint program) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_shader_program *shProg = NULL; - - if (!validate_shader_target(ctx, type)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)"); - return; - } - - if (ctx->TransformFeedback.CurrentObject->Active) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glUseShaderProgramEXT(transform feedback is active)"); - return; - } - - if (program) { - shProg = _mesa_lookup_shader_program_err(ctx, program, - "glUseShaderProgramEXT"); - if (shProg == NULL) - return; - - if (!shProg->LinkStatus) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glUseShaderProgramEXT(program not linked)"); - return; - } - } - - _mesa_use_shader_program(ctx, type, shProg); -} - -void GLAPIENTRY -_mesa_ActiveProgramEXT(GLuint program) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_shader_program *shProg = (program != 0) - ? _mesa_lookup_shader_program_err(ctx, program, "glActiveProgramEXT") - : NULL; - - _mesa_active_program(ctx, shProg, "glActiveProgramEXT"); - return; -} - -GLuint GLAPIENTRY -_mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string) -{ - GET_CURRENT_CONTEXT(ctx); - const GLuint shader = create_shader(ctx, type); - GLuint program = 0; - - if (shader) { - shader_source(ctx, shader, _mesa_strdup(string)); - compile_shader(ctx, shader); - - program = create_shader_program(ctx); - if (program) { - struct gl_shader_program *shProg; - struct gl_shader *sh; - GLint compiled = GL_FALSE; - - shProg = _mesa_lookup_shader_program(ctx, program); - sh = _mesa_lookup_shader(ctx, shader); - - get_shaderiv(ctx, shader, GL_COMPILE_STATUS, &compiled); - if (compiled) { - attach_shader(ctx, program, shader); - link_program(ctx, program); - detach_shader(ctx, program, shader); - -#if 0 - /* Possibly... */ - if (active-user-defined-varyings-in-linked-program) { - append-error-to-info-log; - shProg->LinkStatus = GL_FALSE; - } -#endif - } - - ralloc_strcat(&shProg->InfoLog, sh->InfoLog); - } - - delete_shader(ctx, shader); - } - - return program; -} - -/** - * Plug in shader-related functions into API dispatch table. - */ -void -_mesa_init_shader_dispatch(struct _glapi_table *exec) -{ -#if FEATURE_GL - /* GL_ARB_vertex/fragment_shader */ - SET_DeleteObjectARB(exec, _mesa_DeleteObjectARB); - SET_GetHandleARB(exec, _mesa_GetHandleARB); - SET_DetachObjectARB(exec, _mesa_DetachObjectARB); - SET_CreateShaderObjectARB(exec, _mesa_CreateShaderObjectARB); - SET_ShaderSourceARB(exec, _mesa_ShaderSourceARB); - SET_CompileShaderARB(exec, _mesa_CompileShaderARB); - SET_CreateProgramObjectARB(exec, _mesa_CreateProgramObjectARB); - SET_AttachObjectARB(exec, _mesa_AttachObjectARB); - SET_LinkProgramARB(exec, _mesa_LinkProgramARB); - SET_UseProgramObjectARB(exec, _mesa_UseProgramObjectARB); - SET_ValidateProgramARB(exec, _mesa_ValidateProgramARB); - SET_GetObjectParameterfvARB(exec, _mesa_GetObjectParameterfvARB); - SET_GetObjectParameterivARB(exec, _mesa_GetObjectParameterivARB); - SET_GetInfoLogARB(exec, _mesa_GetInfoLogARB); - SET_GetAttachedObjectsARB(exec, _mesa_GetAttachedObjectsARB); - SET_GetShaderSourceARB(exec, _mesa_GetShaderSourceARB); - - /* OpenGL 2.0 */ - SET_AttachShader(exec, _mesa_AttachShader); - SET_CreateProgram(exec, _mesa_CreateProgram); - SET_CreateShader(exec, _mesa_CreateShader); - SET_DeleteProgram(exec, _mesa_DeleteProgram); - SET_DeleteShader(exec, _mesa_DeleteShader); - SET_DetachShader(exec, _mesa_DetachShader); - SET_GetAttachedShaders(exec, _mesa_GetAttachedShaders); - SET_GetProgramiv(exec, _mesa_GetProgramiv); - SET_GetProgramInfoLog(exec, _mesa_GetProgramInfoLog); - SET_GetShaderiv(exec, _mesa_GetShaderiv); - SET_GetShaderInfoLog(exec, _mesa_GetShaderInfoLog); - SET_IsProgram(exec, _mesa_IsProgram); - SET_IsShader(exec, _mesa_IsShader); - -#if FEATURE_ARB_vertex_shader - SET_BindAttribLocationARB(exec, _mesa_BindAttribLocationARB); - SET_GetActiveAttribARB(exec, _mesa_GetActiveAttribARB); - SET_GetAttribLocationARB(exec, _mesa_GetAttribLocationARB); -#endif - -#if FEATURE_ARB_geometry_shader4 - SET_ProgramParameteriARB(exec, _mesa_ProgramParameteriARB); -#endif - - SET_UseShaderProgramEXT(exec, _mesa_UseShaderProgramEXT); - SET_ActiveProgramEXT(exec, _mesa_ActiveProgramEXT); - SET_CreateShaderProgramEXT(exec, _mesa_CreateShaderProgramEXT); - - /* GL_EXT_gpu_shader4 / GL 3.0 */ - SET_BindFragDataLocationEXT(exec, _mesa_BindFragDataLocation); - SET_GetFragDataLocationEXT(exec, _mesa_GetFragDataLocation); - - /* GL_ARB_ES2_compatibility */ - SET_ReleaseShaderCompiler(exec, _mesa_ReleaseShaderCompiler); - SET_GetShaderPrecisionFormat(exec, _mesa_GetShaderPrecisionFormat); - -#endif /* FEATURE_GL */ -} - +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2004-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009-2010 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file shaderapi.c + * \author Brian Paul + * + * Implementation of GLSL-related API functions. + * The glUniform* functions are in uniforms.c + * + * + * XXX things to do: + * 1. Check that the right error code is generated for all _mesa_error() calls. + * 2. Insert FLUSH_VERTICES calls in various places + */ + + +#include "main/glheader.h" +#include "main/context.h" +#include "main/dispatch.h" +#include "main/enums.h" +#include "main/hash.h" +#include "main/mfeatures.h" +#include "main/mtypes.h" +#include "main/shaderapi.h" +#include "main/shaderobj.h" +#include "program/program.h" +#include "program/prog_parameter.h" +#include "program/prog_uniform.h" +#include "ralloc.h" +#include +#include "../glsl/glsl_parser_extras.h" + +/** Define this to enable shader substitution (see below) */ +#define SHADER_SUBST 0 + + +/** + * Return mask of GLSL_x flags by examining the MESA_GLSL env var. + */ +static GLbitfield +get_shader_flags(void) +{ + GLbitfield flags = 0x0; + const char *env = _mesa_getenv("MESA_GLSL"); + + if (env) { + if (strstr(env, "dump")) + flags |= GLSL_DUMP; + if (strstr(env, "log")) + flags |= GLSL_LOG; + if (strstr(env, "nopvert")) + flags |= GLSL_NOP_VERT; + if (strstr(env, "nopfrag")) + flags |= GLSL_NOP_FRAG; + if (strstr(env, "nopt")) + flags |= GLSL_NO_OPT; + else if (strstr(env, "opt")) + flags |= GLSL_OPT; + if (strstr(env, "uniform")) + flags |= GLSL_UNIFORMS; + if (strstr(env, "useprog")) + flags |= GLSL_USE_PROG; + } + + return flags; +} + + +/** + * Initialize context's shader state. + */ +void +_mesa_init_shader_state(struct gl_context *ctx) +{ + /* Device drivers may override these to control what kind of instructions + * are generated by the GLSL compiler. + */ + struct gl_shader_compiler_options options; + gl_shader_type sh; + + memset(&options, 0, sizeof(options)); + options.MaxUnrollIterations = 32; + + /* Default pragma settings */ + options.DefaultPragmas.Optimize = GL_TRUE; + + for (sh = 0; sh < MESA_SHADER_TYPES; ++sh) + memcpy(&ctx->ShaderCompilerOptions[sh], &options, sizeof(options)); + + ctx->Shader.Flags = get_shader_flags(); +} + + +/** + * Free the per-context shader-related state. + */ +void +_mesa_free_shader_state(struct gl_context *ctx) +{ + _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentVertexProgram, NULL); + _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentGeometryProgram, + NULL); + _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentFragmentProgram, + NULL); + _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL); +} + + +/** + * Return the size of the given GLSL datatype, in floats (components). + */ +GLint +_mesa_sizeof_glsl_type(GLenum type) +{ + switch (type) { + case GL_FLOAT: + case GL_INT: + case GL_BOOL: + case GL_SAMPLER_1D: + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_1D_SHADOW: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_2D_RECT_ARB: + case GL_SAMPLER_2D_RECT_SHADOW_ARB: + case GL_SAMPLER_1D_ARRAY_EXT: + case GL_SAMPLER_2D_ARRAY_EXT: + case GL_SAMPLER_1D_ARRAY_SHADOW_EXT: + case GL_SAMPLER_2D_ARRAY_SHADOW_EXT: + case GL_SAMPLER_CUBE_SHADOW_EXT: + return 1; + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + case GL_UNSIGNED_INT_VEC2: + case GL_BOOL_VEC2: + return 2; + case GL_FLOAT_VEC3: + case GL_INT_VEC3: + case GL_UNSIGNED_INT_VEC3: + case GL_BOOL_VEC3: + return 3; + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + case GL_UNSIGNED_INT_VEC4: + case GL_BOOL_VEC4: + return 4; + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT2x3: + case GL_FLOAT_MAT2x4: + return 8; /* two float[4] vectors */ + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT3x2: + case GL_FLOAT_MAT3x4: + return 12; /* three float[4] vectors */ + case GL_FLOAT_MAT4: + case GL_FLOAT_MAT4x2: + case GL_FLOAT_MAT4x3: + return 16; /* four float[4] vectors */ + default: + _mesa_problem(NULL, "Invalid type in _mesa_sizeof_glsl_type()"); + return 1; + } +} + + +/** + * Copy string from to , up to maxLength characters, returning + * length of in . + * \param src the strings source + * \param maxLength max chars to copy + * \param length returns number of chars copied + * \param dst the string destination + */ +void +_mesa_copy_string(GLchar *dst, GLsizei maxLength, + GLsizei *length, const GLchar *src) +{ + GLsizei len; + for (len = 0; len < maxLength - 1 && src && src[len]; len++) + dst[len] = src[len]; + if (maxLength > 0) + dst[len] = 0; + if (length) + *length = len; +} + + + +/** + * Confirm that the a shader type is valid and supported by the implementation + * + * \param ctx Current GL context + * \param type Shader target + * + */ +static bool +validate_shader_target(const struct gl_context *ctx, GLenum type) +{ + switch (type) { +#if FEATURE_ARB_fragment_shader + case GL_FRAGMENT_SHADER: + return ctx->Extensions.ARB_fragment_shader; +#endif +#if FEATURE_ARB_vertex_shader + case GL_VERTEX_SHADER: + return ctx->Extensions.ARB_vertex_shader; +#endif +#if FEATURE_ARB_geometry_shader4 + case GL_GEOMETRY_SHADER_ARB: + return ctx->Extensions.ARB_geometry_shader4; +#endif + default: + return false; + } +} + + +/** + * Find the length of the longest transform feedback varying name + * which was specified with glTransformFeedbackVaryings(). + */ +static GLint +longest_feedback_varying_name(const struct gl_shader_program *shProg) +{ + GLuint i; + GLint max = 0; + for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) { + GLint len = strlen(shProg->TransformFeedback.VaryingNames[i]); + if (len > max) + max = len; + } + return max; +} + + + +static GLboolean +is_program(struct gl_context *ctx, GLuint name) +{ + struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name); + return shProg ? GL_TRUE : GL_FALSE; +} + + +static GLboolean +is_shader(struct gl_context *ctx, GLuint name) +{ + struct gl_shader *shader = _mesa_lookup_shader(ctx, name); + return shader ? GL_TRUE : GL_FALSE; +} + + +/** + * Attach shader to a shader program. + */ +static void +attach_shader(struct gl_context *ctx, GLuint program, GLuint shader) +{ + struct gl_shader_program *shProg; + struct gl_shader *sh; + GLuint i, n; + + shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader"); + if (!shProg) + return; + + sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader"); + if (!sh) { + return; + } + + n = shProg->NumShaders; + for (i = 0; i < n; i++) { + if (shProg->Shaders[i] == sh) { + /* The shader is already attched to this program. The + * GL_ARB_shader_objects spec says: + * + * "The error INVALID_OPERATION is generated by AttachObjectARB + * if is already attached to ." + */ + _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader"); + return; + } + } + + /* grow list */ + shProg->Shaders = (struct gl_shader **) + _mesa_realloc(shProg->Shaders, + n * sizeof(struct gl_shader *), + (n + 1) * sizeof(struct gl_shader *)); + if (!shProg->Shaders) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader"); + return; + } + + /* append */ + shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */ + _mesa_reference_shader(ctx, &shProg->Shaders[n], sh); + shProg->NumShaders++; +} + + +static GLint +get_attrib_location(struct gl_context *ctx, GLuint program, const GLchar *name) +{ + struct gl_shader_program *shProg + = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation"); + + if (!shProg) { + return -1; + } + + if (!shProg->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetAttribLocation(program not linked)"); + return -1; + } + + if (!name) + return -1; + + if (shProg->VertexProgram) { + const struct gl_program_parameter_list *attribs = + shProg->VertexProgram->Base.Attributes; + if (attribs) { + GLint i = _mesa_lookup_parameter_index(attribs, -1, name); + if (i >= 0) { + return attribs->Parameters[i].StateIndexes[0]; + } + } + } + return -1; +} + + +static void +bind_attrib_location(struct gl_context *ctx, GLuint program, GLuint index, + const GLchar *name) +{ + struct gl_shader_program *shProg; + const GLint size = -1; /* unknown size */ + GLint i; + GLenum datatype = GL_FLOAT_VEC4; + + shProg = _mesa_lookup_shader_program_err(ctx, program, + "glBindAttribLocation"); + if (!shProg) { + return; + } + + if (!name) + return; + + if (strncmp(name, "gl_", 3) == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindAttribLocation(illegal name)"); + return; + } + + if (index >= ctx->Const.VertexProgram.MaxAttribs) { + _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)"); + return; + } + + /* this will replace the current value if it's already in the list */ + i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index); + if (i < 0) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation"); + return; + } + + /* + * Note that this attribute binding won't go into effect until + * glLinkProgram is called again. + */ +} + + +static void +bind_frag_data_location(struct gl_context *ctx, GLuint program, + GLuint colorNumber, const GLchar *name) +{ + _mesa_problem(ctx, "bind_frag_data_location() not implemented yet"); +} + + +static GLuint +create_shader(struct gl_context *ctx, GLenum type) +{ + struct gl_shader *sh; + GLuint name; + + if (!validate_shader_target(ctx, type)) { + _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)"); + return 0; + } + + name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1); + sh = ctx->Driver.NewShader(ctx, name, type); + _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh); + + return name; +} + + +static GLuint +create_shader_program(struct gl_context *ctx) +{ + GLuint name; + struct gl_shader_program *shProg; + + name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1); + + shProg = ctx->Driver.NewShaderProgram(ctx, name); + + _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg); + + assert(shProg->RefCount == 1); + + return name; +} + + +/** + * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's + * DeleteProgramARB. + */ +static void +delete_shader_program(struct gl_context *ctx, GLuint name) +{ + /* + * NOTE: deleting shaders/programs works a bit differently than + * texture objects (and buffer objects, etc). Shader/program + * handles/IDs exist in the hash table until the object is really + * deleted (refcount==0). With texture objects, the handle/ID is + * removed from the hash table in glDeleteTextures() while the tex + * object itself might linger until its refcount goes to zero. + */ + struct gl_shader_program *shProg; + + shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram"); + if (!shProg) + return; + + shProg->DeletePending = GL_TRUE; + + /* effectively, decr shProg's refcount */ + _mesa_reference_shader_program(ctx, &shProg, NULL); +} + + +static void +delete_shader(struct gl_context *ctx, GLuint shader) +{ + struct gl_shader *sh; + + sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader"); + if (!sh) + return; + + sh->DeletePending = GL_TRUE; + + /* effectively, decr sh's refcount */ + _mesa_reference_shader(ctx, &sh, NULL); +} + + +static void +detach_shader(struct gl_context *ctx, GLuint program, GLuint shader) +{ + struct gl_shader_program *shProg; + GLuint n; + GLuint i, j; + + shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader"); + if (!shProg) + return; + + n = shProg->NumShaders; + + for (i = 0; i < n; i++) { + if (shProg->Shaders[i]->Name == shader) { + /* found it */ + struct gl_shader **newList; + + /* release */ + _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL); + + /* alloc new, smaller array */ + newList = (struct gl_shader **) + malloc((n - 1) * sizeof(struct gl_shader *)); + if (!newList) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader"); + return; + } + for (j = 0; j < i; j++) { + newList[j] = shProg->Shaders[j]; + } + while (++i < n) + newList[j++] = shProg->Shaders[i]; + free(shProg->Shaders); + + shProg->Shaders = newList; + shProg->NumShaders = n - 1; + +#ifdef DEBUG + /* sanity check */ + { + for (j = 0; j < shProg->NumShaders; j++) { + assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER || + shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER); + assert(shProg->Shaders[j]->RefCount > 0); + } + } +#endif + + return; + } + } + + /* not found */ + { + GLenum err; + if (is_shader(ctx, shader)) + err = GL_INVALID_OPERATION; + else if (is_program(ctx, shader)) + err = GL_INVALID_OPERATION; + else + err = GL_INVALID_VALUE; + _mesa_error(ctx, err, "glDetachProgram(shader)"); + return; + } +} + + +static void +get_active_attrib(struct gl_context *ctx, GLuint program, GLuint index, + GLsizei maxLength, GLsizei *length, GLint *size, + GLenum *type, GLchar *nameOut) +{ + const struct gl_program_parameter_list *attribs = NULL; + struct gl_shader_program *shProg; + + shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib"); + if (!shProg) + return; + + if (shProg->VertexProgram) + attribs = shProg->VertexProgram->Base.Attributes; + + if (!attribs || index >= attribs->NumParameters) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)"); + return; + } + + _mesa_copy_string(nameOut, maxLength, length, + attribs->Parameters[index].Name); + + if (size) + *size = attribs->Parameters[index].Size + / _mesa_sizeof_glsl_type(attribs->Parameters[index].DataType); + + if (type) + *type = attribs->Parameters[index].DataType; +} + + +/** + * Return list of shaders attached to shader program. + */ +static void +get_attached_shaders(struct gl_context *ctx, GLuint program, GLsizei maxCount, + GLsizei *count, GLuint *obj) +{ + struct gl_shader_program *shProg = + _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders"); + if (shProg) { + GLuint i; + for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) { + obj[i] = shProg->Shaders[i]->Name; + } + if (count) + *count = i; + } +} + + +static GLint +get_frag_data_location(struct gl_context *ctx, GLuint program, + const GLchar *name) +{ + _mesa_problem(ctx, "get_frag_data_location() not implemented yet"); + return -1; +} + + + +/** + * glGetHandleARB() - return ID/name of currently bound shader program. + */ +static GLuint +get_handle(struct gl_context *ctx, GLenum pname) +{ + if (pname == GL_PROGRAM_OBJECT_ARB) { + if (ctx->Shader.ActiveProgram) + return ctx->Shader.ActiveProgram->Name; + else + return 0; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB"); + return 0; + } +} + + +/** + * glGetProgramiv() - get shader program state. + * Note that this is for GLSL shader programs, not ARB vertex/fragment + * programs (see glGetProgramivARB). + */ +static void +get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *params) +{ + const struct gl_program_parameter_list *attribs; + struct gl_shader_program *shProg + = _mesa_lookup_shader_program(ctx, program); + + if (!shProg) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)"); + return; + } + + if (shProg->VertexProgram) + attribs = shProg->VertexProgram->Base.Attributes; + else + attribs = NULL; + + switch (pname) { + case GL_DELETE_STATUS: + *params = shProg->DeletePending; + break; + case GL_LINK_STATUS: + *params = shProg->LinkStatus; + break; + case GL_VALIDATE_STATUS: + *params = shProg->Validated; + break; + case GL_INFO_LOG_LENGTH: + *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0; + break; + case GL_ATTACHED_SHADERS: + *params = shProg->NumShaders; + break; + case GL_ACTIVE_ATTRIBUTES: + *params = attribs ? attribs->NumParameters : 0; + break; + case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: + *params = _mesa_longest_parameter_name(attribs, PROGRAM_INPUT) + 1; + break; + case GL_ACTIVE_UNIFORMS: + *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0; + break; + case GL_ACTIVE_UNIFORM_MAX_LENGTH: + *params = _mesa_longest_uniform_name(shProg->Uniforms); + if (*params > 0) + (*params)++; /* add one for terminating zero */ + break; + case GL_PROGRAM_BINARY_LENGTH_OES: + *params = 0; + break; +#if FEATURE_EXT_transform_feedback + case GL_TRANSFORM_FEEDBACK_VARYINGS: + *params = shProg->TransformFeedback.NumVarying; + break; + case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: + *params = longest_feedback_varying_name(shProg) + 1; + break; + case GL_TRANSFORM_FEEDBACK_BUFFER_MODE: + *params = shProg->TransformFeedback.BufferMode; + break; +#endif +#if FEATURE_ARB_geometry_shader4 + case GL_GEOMETRY_VERTICES_OUT_ARB: + *params = shProg->Geom.VerticesOut; + break; + case GL_GEOMETRY_INPUT_TYPE_ARB: + *params = shProg->Geom.InputType; + break; + case GL_GEOMETRY_OUTPUT_TYPE_ARB: + *params = shProg->Geom.OutputType; + break; +#endif + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)"); + return; + } +} + + +/** + * glGetShaderiv() - get GLSL shader state + */ +static void +get_shaderiv(struct gl_context *ctx, GLuint name, GLenum pname, GLint *params) +{ + struct gl_shader *shader = + _mesa_lookup_shader_err(ctx, name, "glGetShaderiv"); + + if (!shader) { + return; + } + + switch (pname) { + case GL_SHADER_TYPE: + *params = shader->Type; + break; + case GL_DELETE_STATUS: + *params = shader->DeletePending; + break; + case GL_COMPILE_STATUS: + *params = shader->CompileStatus; + break; + case GL_INFO_LOG_LENGTH: + *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0; + break; + case GL_SHADER_SOURCE_LENGTH: + *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)"); + return; + } +} + + +static void +get_program_info_log(struct gl_context *ctx, GLuint program, GLsizei bufSize, + GLsizei *length, GLchar *infoLog) +{ + struct gl_shader_program *shProg + = _mesa_lookup_shader_program(ctx, program); + if (!shProg) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)"); + return; + } + _mesa_copy_string(infoLog, bufSize, length, shProg->InfoLog); +} + + +static void +get_shader_info_log(struct gl_context *ctx, GLuint shader, GLsizei bufSize, + GLsizei *length, GLchar *infoLog) +{ + struct gl_shader *sh = _mesa_lookup_shader(ctx, shader); + if (!sh) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)"); + return; + } + _mesa_copy_string(infoLog, bufSize, length, sh->InfoLog); +} + + +/** + * Return shader source code. + */ +static void +get_shader_source(struct gl_context *ctx, GLuint shader, GLsizei maxLength, + GLsizei *length, GLchar *sourceOut) +{ + struct gl_shader *sh; + sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource"); + if (!sh) { + return; + } + _mesa_copy_string(sourceOut, maxLength, length, sh->Source); +} + + +/** + * Set/replace shader source code. + */ +static void +shader_source(struct gl_context *ctx, GLuint shader, const GLchar *source) +{ + struct gl_shader *sh; + + sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource"); + if (!sh) + return; + + /* free old shader source string and install new one */ + if (sh->Source) { + free((void *) sh->Source); + } + sh->Source = source; + sh->CompileStatus = GL_FALSE; +#ifdef DEBUG + sh->SourceChecksum = _mesa_str_checksum(sh->Source); +#endif +} + + +/** + * Compile a shader. + */ +static void +compile_shader(struct gl_context *ctx, GLuint shaderObj) +{ + struct gl_shader *sh; + struct gl_shader_compiler_options *options; + + sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader"); + if (!sh) + return; + + options = &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(sh->Type)]; + + /* set default pragma state for shader */ + sh->Pragmas = options->DefaultPragmas; + + /* this call will set the sh->CompileStatus field to indicate if + * compilation was successful. + */ + _mesa_glsl_compile_shader(ctx, sh); +} + + +/** + * Link a program's shaders. + */ +static void +link_program(struct gl_context *ctx, GLuint program) +{ + struct gl_shader_program *shProg; + struct gl_transform_feedback_object *obj = + ctx->TransformFeedback.CurrentObject; + + shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram"); + if (!shProg) + return; + + if (obj->Active + && (shProg == ctx->Shader.CurrentVertexProgram + || shProg == ctx->Shader.CurrentGeometryProgram + || shProg == ctx->Shader.CurrentFragmentProgram)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glLinkProgram(transform feedback active"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + _mesa_glsl_link_shader(ctx, shProg); + + /* debug code */ + if (0) { + GLuint i; + + printf("Link %u shaders in program %u: %s\n", + shProg->NumShaders, shProg->Name, + shProg->LinkStatus ? "Success" : "Failed"); + + for (i = 0; i < shProg->NumShaders; i++) { + printf(" shader %u, type 0x%x\n", + shProg->Shaders[i]->Name, + shProg->Shaders[i]->Type); + } + } +} + + +/** + * Print basic shader info (for debug). + */ +static void +print_shader_info(const struct gl_shader_program *shProg) +{ + GLuint i; + + printf("Mesa: glUseProgram(%u)\n", shProg->Name); + for (i = 0; i < shProg->NumShaders; i++) { + const char *s; + switch (shProg->Shaders[i]->Type) { + case GL_VERTEX_SHADER: + s = "vertex"; + break; + case GL_FRAGMENT_SHADER: + s = "fragment"; + break; + case GL_GEOMETRY_SHADER: + s = "geometry"; + break; + default: + s = ""; + } + printf(" %s shader %u, checksum %u\n", s, + shProg->Shaders[i]->Name, + shProg->Shaders[i]->SourceChecksum); + } + if (shProg->VertexProgram) + printf(" vert prog %u\n", shProg->VertexProgram->Base.Id); + if (shProg->FragmentProgram) + printf(" frag prog %u\n", shProg->FragmentProgram->Base.Id); +} + + +/** + * Use the named shader program for subsequent glUniform calls + */ +void +_mesa_active_program(struct gl_context *ctx, struct gl_shader_program *shProg, + const char *caller) +{ + if ((shProg != NULL) && !shProg->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(program %u not linked)", caller, shProg->Name); + return; + } + + if (ctx->Shader.ActiveProgram != shProg) { + _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, shProg); + } +} + +/** + */ +static bool +use_shader_program(struct gl_context *ctx, GLenum type, + struct gl_shader_program *shProg) +{ + struct gl_shader_program **target; + + switch (type) { +#if FEATURE_ARB_vertex_shader + case GL_VERTEX_SHADER: + target = &ctx->Shader.CurrentVertexProgram; + if ((shProg == NULL) + || (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)) { + shProg = NULL; + } + break; +#endif +#if FEATURE_ARB_geometry_shader4 + case GL_GEOMETRY_SHADER_ARB: + target = &ctx->Shader.CurrentGeometryProgram; + if ((shProg == NULL) + || (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY] == NULL)) { + shProg = NULL; + } + break; +#endif +#if FEATURE_ARB_fragment_shader + case GL_FRAGMENT_SHADER: + target = &ctx->Shader.CurrentFragmentProgram; + if ((shProg == NULL) + || (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)) { + shProg = NULL; + } + break; +#endif + default: + return false; + } + + if (*target != shProg) { + FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); + _mesa_reference_shader_program(ctx, target, shProg); + return true; + } + + return false; +} + +/** + * Use the named shader program for subsequent rendering. + */ +void +_mesa_use_program(struct gl_context *ctx, struct gl_shader_program *shProg) +{ + use_shader_program(ctx, GL_VERTEX_SHADER, shProg); + use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB, shProg); + use_shader_program(ctx, GL_FRAGMENT_SHADER, shProg); + _mesa_active_program(ctx, shProg, "glUseProgram"); + + if (ctx->Driver.UseProgram) + ctx->Driver.UseProgram(ctx, shProg); +} + + +/** + * Validate a program's samplers. + * Specifically, check that there aren't two samplers of different types + * pointing to the same texture unit. + * \return GL_TRUE if valid, GL_FALSE if invalid + */ +static GLboolean +validate_samplers(const struct gl_program *prog, char *errMsg) +{ + static const char *targetName[] = { + "TEXTURE_BUFFER", + "TEXTURE_2D_ARRAY", + "TEXTURE_1D_ARRAY", + "TEXTURE_CUBE", + "TEXTURE_3D", + "TEXTURE_RECT", + "TEXTURE_2D", + "TEXTURE_1D", + }; + GLint targetUsed[MAX_TEXTURE_IMAGE_UNITS]; + GLbitfield samplersUsed = prog->SamplersUsed; + GLuint i; + + assert(Elements(targetName) == NUM_TEXTURE_TARGETS); + + if (samplersUsed == 0x0) + return GL_TRUE; + + for (i = 0; i < Elements(targetUsed); i++) + targetUsed[i] = -1; + + /* walk over bits which are set in 'samplers' */ + while (samplersUsed) { + GLuint unit; + gl_texture_index target; + GLint sampler = _mesa_ffs(samplersUsed) - 1; + assert(sampler >= 0); + assert(sampler < MAX_TEXTURE_IMAGE_UNITS); + unit = prog->SamplerUnits[sampler]; + target = prog->SamplerTargets[sampler]; + if (targetUsed[unit] != -1 && targetUsed[unit] != (int) target) { + _mesa_snprintf(errMsg, 100, + "Texture unit %d is accessed both as %s and %s", + unit, targetName[targetUsed[unit]], targetName[target]); + return GL_FALSE; + } + targetUsed[unit] = target; + samplersUsed ^= (1 << sampler); + } + + return GL_TRUE; +} + + +/** + * Do validation of the given shader program. + * \param errMsg returns error message if validation fails. + * \return GL_TRUE if valid, GL_FALSE if invalid (and set errMsg) + */ +static GLboolean +validate_shader_program(const struct gl_shader_program *shProg, + char *errMsg) +{ + const struct gl_vertex_program *vp = shProg->VertexProgram; + const struct gl_fragment_program *fp = shProg->FragmentProgram; + + if (!shProg->LinkStatus) { + return GL_FALSE; + } + + /* From the GL spec, a program is invalid if any of these are true: + + any two active samplers in the current program object are of + different types, but refer to the same texture image unit, + + any active sampler in the current program object refers to a texture + image unit where fixed-function fragment processing accesses a + texture target that does not match the sampler type, or + + the sum of the number of active samplers in the program and the + number of texture image units enabled for fixed-function fragment + processing exceeds the combined limit on the total number of texture + image units allowed. + */ + + + /* + * Check: any two active samplers in the current program object are of + * different types, but refer to the same texture image unit, + */ + if (vp && !validate_samplers(&vp->Base, errMsg)) { + return GL_FALSE; + } + if (fp && !validate_samplers(&fp->Base, errMsg)) { + return GL_FALSE; + } + + return GL_TRUE; +} + + +/** + * Called via glValidateProgram() + */ +static void +validate_program(struct gl_context *ctx, GLuint program) +{ + struct gl_shader_program *shProg; + char errMsg[100]; + + shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram"); + if (!shProg) { + return; + } + + shProg->Validated = validate_shader_program(shProg, errMsg); + if (!shProg->Validated) { + /* update info log */ + if (shProg->InfoLog) { + ralloc_free(shProg->InfoLog); + } + shProg->InfoLog = ralloc_strdup(shProg, errMsg); + } +} + + + +void GLAPIENTRY +_mesa_AttachObjectARB(GLhandleARB program, GLhandleARB shader) +{ + GET_CURRENT_CONTEXT(ctx); + attach_shader(ctx, program, shader); +} + + +void GLAPIENTRY +_mesa_AttachShader(GLuint program, GLuint shader) +{ + GET_CURRENT_CONTEXT(ctx); + attach_shader(ctx, program, shader); +} + + +void GLAPIENTRY +_mesa_BindAttribLocationARB(GLhandleARB program, GLuint index, + const GLcharARB *name) +{ + GET_CURRENT_CONTEXT(ctx); + bind_attrib_location(ctx, program, index, name); +} + + +/* GL_EXT_gpu_shader4, GL3 */ +void GLAPIENTRY +_mesa_BindFragDataLocation(GLuint program, GLuint colorNumber, + const GLchar *name) +{ + GET_CURRENT_CONTEXT(ctx); + bind_frag_data_location(ctx, program, colorNumber, name); +} + + +void GLAPIENTRY +_mesa_CompileShaderARB(GLhandleARB shaderObj) +{ + GET_CURRENT_CONTEXT(ctx); + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glCompileShader %u\n", shaderObj); + compile_shader(ctx, shaderObj); +} + + +GLuint GLAPIENTRY +_mesa_CreateShader(GLenum type) +{ + GET_CURRENT_CONTEXT(ctx); + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glCreateShader %s\n", _mesa_lookup_enum_by_nr(type)); + return create_shader(ctx, type); +} + + +GLhandleARB GLAPIENTRY +_mesa_CreateShaderObjectARB(GLenum type) +{ + GET_CURRENT_CONTEXT(ctx); + return create_shader(ctx, type); +} + + +GLuint GLAPIENTRY +_mesa_CreateProgram(void) +{ + GET_CURRENT_CONTEXT(ctx); + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glCreateProgram\n"); + return create_shader_program(ctx); +} + + +GLhandleARB GLAPIENTRY +_mesa_CreateProgramObjectARB(void) +{ + GET_CURRENT_CONTEXT(ctx); + return create_shader_program(ctx); +} + + +void GLAPIENTRY +_mesa_DeleteObjectARB(GLhandleARB obj) +{ + if (MESA_VERBOSE & VERBOSE_API) { + GET_CURRENT_CONTEXT(ctx); + _mesa_debug(ctx, "glDeleteObjectARB(%u)\n", obj); + } + + if (obj) { + GET_CURRENT_CONTEXT(ctx); + FLUSH_VERTICES(ctx, 0); + if (is_program(ctx, obj)) { + delete_shader_program(ctx, obj); + } + else if (is_shader(ctx, obj)) { + delete_shader(ctx, obj); + } + else { + /* error? */ + } + } +} + + +void GLAPIENTRY +_mesa_DeleteProgram(GLuint name) +{ + if (name) { + GET_CURRENT_CONTEXT(ctx); + FLUSH_VERTICES(ctx, 0); + delete_shader_program(ctx, name); + } +} + + +void GLAPIENTRY +_mesa_DeleteShader(GLuint name) +{ + if (name) { + GET_CURRENT_CONTEXT(ctx); + FLUSH_VERTICES(ctx, 0); + delete_shader(ctx, name); + } +} + + +void GLAPIENTRY +_mesa_DetachObjectARB(GLhandleARB program, GLhandleARB shader) +{ + GET_CURRENT_CONTEXT(ctx); + detach_shader(ctx, program, shader); +} + + +void GLAPIENTRY +_mesa_DetachShader(GLuint program, GLuint shader) +{ + GET_CURRENT_CONTEXT(ctx); + detach_shader(ctx, program, shader); +} + + +void GLAPIENTRY +_mesa_GetActiveAttribARB(GLhandleARB program, GLuint index, + GLsizei maxLength, GLsizei * length, GLint * size, + GLenum * type, GLcharARB * name) +{ + GET_CURRENT_CONTEXT(ctx); + get_active_attrib(ctx, program, index, maxLength, length, size, type, name); +} + + +void GLAPIENTRY +_mesa_GetAttachedObjectsARB(GLhandleARB container, GLsizei maxCount, + GLsizei * count, GLhandleARB * obj) +{ + GET_CURRENT_CONTEXT(ctx); + get_attached_shaders(ctx, container, maxCount, count, obj); +} + + +void GLAPIENTRY +_mesa_GetAttachedShaders(GLuint program, GLsizei maxCount, + GLsizei *count, GLuint *obj) +{ + GET_CURRENT_CONTEXT(ctx); + get_attached_shaders(ctx, program, maxCount, count, obj); +} + + +GLint GLAPIENTRY +_mesa_GetAttribLocationARB(GLhandleARB program, const GLcharARB * name) +{ + GET_CURRENT_CONTEXT(ctx); + return get_attrib_location(ctx, program, name); +} + + +/* GL_EXT_gpu_shader4, GL3 */ +GLint GLAPIENTRY +_mesa_GetFragDataLocation(GLuint program, const GLchar *name) +{ + GET_CURRENT_CONTEXT(ctx); + return get_frag_data_location(ctx, program, name); +} + + + +void GLAPIENTRY +_mesa_GetInfoLogARB(GLhandleARB object, GLsizei maxLength, GLsizei * length, + GLcharARB * infoLog) +{ + GET_CURRENT_CONTEXT(ctx); + if (is_program(ctx, object)) { + get_program_info_log(ctx, object, maxLength, length, infoLog); + } + else if (is_shader(ctx, object)) { + get_shader_info_log(ctx, object, maxLength, length, infoLog); + } + else { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetInfoLogARB"); + } +} + + +void GLAPIENTRY +_mesa_GetObjectParameterivARB(GLhandleARB object, GLenum pname, GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + /* Implement in terms of GetProgramiv, GetShaderiv */ + if (is_program(ctx, object)) { + if (pname == GL_OBJECT_TYPE_ARB) { + *params = GL_PROGRAM_OBJECT_ARB; + } + else { + get_programiv(ctx, object, pname, params); + } + } + else if (is_shader(ctx, object)) { + if (pname == GL_OBJECT_TYPE_ARB) { + *params = GL_SHADER_OBJECT_ARB; + } + else { + get_shaderiv(ctx, object, pname, params); + } + } + else { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetObjectParameterivARB"); + } +} + + +void GLAPIENTRY +_mesa_GetObjectParameterfvARB(GLhandleARB object, GLenum pname, + GLfloat *params) +{ + GLint iparams[1]; /* XXX is one element enough? */ + _mesa_GetObjectParameterivARB(object, pname, iparams); + params[0] = (GLfloat) iparams[0]; +} + + +void GLAPIENTRY +_mesa_GetProgramiv(GLuint program, GLenum pname, GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + get_programiv(ctx, program, pname, params); +} + + +void GLAPIENTRY +_mesa_GetShaderiv(GLuint shader, GLenum pname, GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + get_shaderiv(ctx, shader, pname, params); +} + + +void GLAPIENTRY +_mesa_GetProgramInfoLog(GLuint program, GLsizei bufSize, + GLsizei *length, GLchar *infoLog) +{ + GET_CURRENT_CONTEXT(ctx); + get_program_info_log(ctx, program, bufSize, length, infoLog); +} + + +void GLAPIENTRY +_mesa_GetShaderInfoLog(GLuint shader, GLsizei bufSize, + GLsizei *length, GLchar *infoLog) +{ + GET_CURRENT_CONTEXT(ctx); + get_shader_info_log(ctx, shader, bufSize, length, infoLog); +} + + +void GLAPIENTRY +_mesa_GetShaderSourceARB(GLhandleARB shader, GLsizei maxLength, + GLsizei *length, GLcharARB *sourceOut) +{ + GET_CURRENT_CONTEXT(ctx); + get_shader_source(ctx, shader, maxLength, length, sourceOut); +} + + +GLhandleARB GLAPIENTRY +_mesa_GetHandleARB(GLenum pname) +{ + GET_CURRENT_CONTEXT(ctx); + return get_handle(ctx, pname); +} + + +GLboolean GLAPIENTRY +_mesa_IsProgram(GLuint name) +{ + GET_CURRENT_CONTEXT(ctx); + return is_program(ctx, name); +} + + +GLboolean GLAPIENTRY +_mesa_IsShader(GLuint name) +{ + GET_CURRENT_CONTEXT(ctx); + return is_shader(ctx, name); +} + + +void GLAPIENTRY +_mesa_LinkProgramARB(GLhandleARB programObj) +{ + GET_CURRENT_CONTEXT(ctx); + link_program(ctx, programObj); +} + + + +/** + * Read shader source code from a file. + * Useful for debugging to override an app's shader. + */ +static GLcharARB * +read_shader(const char *fname) +{ + const int max = 50*1000; + FILE *f = fopen(fname, "r"); + GLcharARB *buffer, *shader; + int len; + + if (!f) { + return NULL; + } + + buffer = (char *) malloc(max); + len = fread(buffer, 1, max, f); + buffer[len] = 0; + + fclose(f); + + shader = _mesa_strdup(buffer); + free(buffer); + + return shader; +} + + +/** + * Called via glShaderSource() and glShaderSourceARB() API functions. + * Basically, concatenate the source code strings into one long string + * and pass it to _mesa_shader_source(). + */ +void GLAPIENTRY +_mesa_ShaderSourceARB(GLhandleARB shaderObj, GLsizei count, + const GLcharARB ** string, const GLint * length) +{ + GET_CURRENT_CONTEXT(ctx); + GLint *offsets; + GLsizei i, totalLength; + GLcharARB *source; + GLuint checksum; + + if (!shaderObj || string == NULL) { + _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB"); + return; + } + + /* + * This array holds offsets of where the appropriate string ends, thus the + * last element will be set to the total length of the source code. + */ + offsets = (GLint *) malloc(count * sizeof(GLint)); + if (offsets == NULL) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB"); + return; + } + + for (i = 0; i < count; i++) { + if (string[i] == NULL) { + free((GLvoid *) offsets); + _mesa_error(ctx, GL_INVALID_OPERATION, "glShaderSourceARB(null string)"); + return; + } + if (length == NULL || length[i] < 0) + offsets[i] = strlen(string[i]); + else + offsets[i] = length[i]; + /* accumulate string lengths */ + if (i > 0) + offsets[i] += offsets[i - 1]; + } + + /* Total length of source string is sum off all strings plus two. + * One extra byte for terminating zero, another extra byte to silence + * valgrind warnings in the parser/grammer code. + */ + totalLength = offsets[count - 1] + 2; + source = (GLcharARB *) malloc(totalLength * sizeof(GLcharARB)); + if (source == NULL) { + free((GLvoid *) offsets); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB"); + return; + } + + for (i = 0; i < count; i++) { + GLint start = (i > 0) ? offsets[i - 1] : 0; + memcpy(source + start, string[i], + (offsets[i] - start) * sizeof(GLcharARB)); + } + source[totalLength - 1] = '\0'; + source[totalLength - 2] = '\0'; + + if (SHADER_SUBST) { + /* Compute the shader's source code checksum then try to open a file + * named newshader_. If it exists, use it in place of the + * original shader source code. For debugging. + */ + char filename[100]; + GLcharARB *newSource; + + checksum = _mesa_str_checksum(source); + + _mesa_snprintf(filename, sizeof(filename), "newshader_%d", checksum); + + newSource = read_shader(filename); + if (newSource) { + fprintf(stderr, "Mesa: Replacing shader %u chksum=%d with %s\n", + shaderObj, checksum, filename); + free(source); + source = newSource; + } + } + + shader_source(ctx, shaderObj, source); + + if (SHADER_SUBST) { + struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj); + if (sh) + sh->SourceChecksum = checksum; /* save original checksum */ + } + + free(offsets); +} + + +void GLAPIENTRY +_mesa_UseProgramObjectARB(GLhandleARB program) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_shader_program *shProg; + struct gl_transform_feedback_object *obj = + ctx->TransformFeedback.CurrentObject; + + if (obj->Active) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUseProgram(transform feedback active)"); + return; + } + + if (program) { + shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram"); + if (!shProg) { + return; + } + if (!shProg->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUseProgram(program %u not linked)", program); + return; + } + + /* debug code */ + if (ctx->Shader.Flags & GLSL_USE_PROG) { + print_shader_info(shProg); + } + } + else { + shProg = NULL; + } + + _mesa_use_program(ctx, shProg); +} + + +void GLAPIENTRY +_mesa_ValidateProgramARB(GLhandleARB program) +{ + GET_CURRENT_CONTEXT(ctx); + validate_program(ctx, program); +} + +#ifdef FEATURE_ES2 + +void GLAPIENTRY +_mesa_GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, + GLint* range, GLint* precision) +{ + const struct gl_program_constants *limits; + const struct gl_precision *p; + GET_CURRENT_CONTEXT(ctx); + + switch (shadertype) { + case GL_VERTEX_SHADER: + limits = &ctx->Const.VertexProgram; + break; + case GL_FRAGMENT_SHADER: + limits = &ctx->Const.FragmentProgram; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetShaderPrecisionFormat(shadertype)"); + return; + } + + switch (precisiontype) { + case GL_LOW_FLOAT: + p = &limits->LowFloat; + break; + case GL_MEDIUM_FLOAT: + p = &limits->MediumFloat; + break; + case GL_HIGH_FLOAT: + p = &limits->HighFloat; + break; + case GL_LOW_INT: + p = &limits->LowInt; + break; + case GL_MEDIUM_INT: + p = &limits->MediumInt; + break; + case GL_HIGH_INT: + p = &limits->HighInt; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetShaderPrecisionFormat(precisiontype)"); + return; + } + + range[0] = p->RangeMin; + range[1] = p->RangeMax; + precision[0] = p->Precision; +} + + +void GLAPIENTRY +_mesa_ReleaseShaderCompiler(void) +{ + _mesa_destroy_shader_compiler_caches(); +} + + +void GLAPIENTRY +_mesa_ShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, + const void* binary, GLint length) +{ + GET_CURRENT_CONTEXT(ctx); + (void) n; + (void) shaders; + (void) binaryformat; + (void) binary; + (void) length; + _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__); +} + +#endif /* FEATURE_ES2 */ + + +#if FEATURE_ARB_geometry_shader4 + +void GLAPIENTRY +_mesa_ProgramParameteriARB(GLuint program, GLenum pname, + GLint value) +{ + struct gl_shader_program *shProg; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + shProg = _mesa_lookup_shader_program_err(ctx, program, + "glProgramParameteri"); + if (!shProg) + return; + + switch (pname) { + case GL_GEOMETRY_VERTICES_OUT_ARB: + if (value < 1 || + (unsigned) value > ctx->Const.MaxGeometryOutputVertices) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glProgramParameteri(GL_GEOMETRY_VERTICES_OUT_ARB=%d", + value); + return; + } + shProg->Geom.VerticesOut = value; + break; + case GL_GEOMETRY_INPUT_TYPE_ARB: + switch (value) { + case GL_POINTS: + case GL_LINES: + case GL_LINES_ADJACENCY_ARB: + case GL_TRIANGLES: + case GL_TRIANGLES_ADJACENCY_ARB: + shProg->Geom.InputType = value; + break; + default: + _mesa_error(ctx, GL_INVALID_VALUE, + "glProgramParameteri(geometry input type = %s", + _mesa_lookup_enum_by_nr(value)); + return; + } + break; + case GL_GEOMETRY_OUTPUT_TYPE_ARB: + switch (value) { + case GL_POINTS: + case GL_LINE_STRIP: + case GL_TRIANGLE_STRIP: + shProg->Geom.OutputType = value; + break; + default: + _mesa_error(ctx, GL_INVALID_VALUE, + "glProgramParameteri(geometry output type = %s", + _mesa_lookup_enum_by_nr(value)); + return; + } + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameteriARB(pname=%s)", + _mesa_lookup_enum_by_nr(pname)); + break; + } +} + +#endif + +void +_mesa_use_shader_program(struct gl_context *ctx, GLenum type, + struct gl_shader_program *shProg) +{ + use_shader_program(ctx, type, shProg); + + if (ctx->Driver.UseProgram) + ctx->Driver.UseProgram(ctx, shProg); +} + +void GLAPIENTRY +_mesa_UseShaderProgramEXT(GLenum type, GLuint program) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_shader_program *shProg = NULL; + + if (!validate_shader_target(ctx, type)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)"); + return; + } + + if (ctx->TransformFeedback.CurrentObject->Active) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUseShaderProgramEXT(transform feedback is active)"); + return; + } + + if (program) { + shProg = _mesa_lookup_shader_program_err(ctx, program, + "glUseShaderProgramEXT"); + if (shProg == NULL) + return; + + if (!shProg->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUseShaderProgramEXT(program not linked)"); + return; + } + } + + _mesa_use_shader_program(ctx, type, shProg); +} + +void GLAPIENTRY +_mesa_ActiveProgramEXT(GLuint program) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_shader_program *shProg = (program != 0) + ? _mesa_lookup_shader_program_err(ctx, program, "glActiveProgramEXT") + : NULL; + + _mesa_active_program(ctx, shProg, "glActiveProgramEXT"); + return; +} + +GLuint GLAPIENTRY +_mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string) +{ + GET_CURRENT_CONTEXT(ctx); + const GLuint shader = create_shader(ctx, type); + GLuint program = 0; + + if (shader) { + shader_source(ctx, shader, _mesa_strdup(string)); + compile_shader(ctx, shader); + + program = create_shader_program(ctx); + if (program) { + struct gl_shader_program *shProg; + struct gl_shader *sh; + GLint compiled = GL_FALSE; + + shProg = _mesa_lookup_shader_program(ctx, program); + sh = _mesa_lookup_shader(ctx, shader); + + get_shaderiv(ctx, shader, GL_COMPILE_STATUS, &compiled); + if (compiled) { + attach_shader(ctx, program, shader); + link_program(ctx, program); + detach_shader(ctx, program, shader); + +#if 0 + /* Possibly... */ + if (active-user-defined-varyings-in-linked-program) { + append-error-to-info-log; + shProg->LinkStatus = GL_FALSE; + } +#endif + } + + ralloc_strcat(&shProg->InfoLog, sh->InfoLog); + } + + delete_shader(ctx, shader); + } + + return program; +} + +/** + * Plug in shader-related functions into API dispatch table. + */ +void +_mesa_init_shader_dispatch(struct _glapi_table *exec) +{ +#if FEATURE_GL + /* GL_ARB_vertex/fragment_shader */ + SET_DeleteObjectARB(exec, _mesa_DeleteObjectARB); + SET_GetHandleARB(exec, _mesa_GetHandleARB); + SET_DetachObjectARB(exec, _mesa_DetachObjectARB); + SET_CreateShaderObjectARB(exec, _mesa_CreateShaderObjectARB); + SET_ShaderSourceARB(exec, _mesa_ShaderSourceARB); + SET_CompileShaderARB(exec, _mesa_CompileShaderARB); + SET_CreateProgramObjectARB(exec, _mesa_CreateProgramObjectARB); + SET_AttachObjectARB(exec, _mesa_AttachObjectARB); + SET_LinkProgramARB(exec, _mesa_LinkProgramARB); + SET_UseProgramObjectARB(exec, _mesa_UseProgramObjectARB); + SET_ValidateProgramARB(exec, _mesa_ValidateProgramARB); + SET_GetObjectParameterfvARB(exec, _mesa_GetObjectParameterfvARB); + SET_GetObjectParameterivARB(exec, _mesa_GetObjectParameterivARB); + SET_GetInfoLogARB(exec, _mesa_GetInfoLogARB); + SET_GetAttachedObjectsARB(exec, _mesa_GetAttachedObjectsARB); + SET_GetShaderSourceARB(exec, _mesa_GetShaderSourceARB); + + /* OpenGL 2.0 */ + SET_AttachShader(exec, _mesa_AttachShader); + SET_CreateProgram(exec, _mesa_CreateProgram); + SET_CreateShader(exec, _mesa_CreateShader); + SET_DeleteProgram(exec, _mesa_DeleteProgram); + SET_DeleteShader(exec, _mesa_DeleteShader); + SET_DetachShader(exec, _mesa_DetachShader); + SET_GetAttachedShaders(exec, _mesa_GetAttachedShaders); + SET_GetProgramiv(exec, _mesa_GetProgramiv); + SET_GetProgramInfoLog(exec, _mesa_GetProgramInfoLog); + SET_GetShaderiv(exec, _mesa_GetShaderiv); + SET_GetShaderInfoLog(exec, _mesa_GetShaderInfoLog); + SET_IsProgram(exec, _mesa_IsProgram); + SET_IsShader(exec, _mesa_IsShader); + +#if FEATURE_ARB_vertex_shader + SET_BindAttribLocationARB(exec, _mesa_BindAttribLocationARB); + SET_GetActiveAttribARB(exec, _mesa_GetActiveAttribARB); + SET_GetAttribLocationARB(exec, _mesa_GetAttribLocationARB); +#endif + +#if FEATURE_ARB_geometry_shader4 + SET_ProgramParameteriARB(exec, _mesa_ProgramParameteriARB); +#endif + + SET_UseShaderProgramEXT(exec, _mesa_UseShaderProgramEXT); + SET_ActiveProgramEXT(exec, _mesa_ActiveProgramEXT); + SET_CreateShaderProgramEXT(exec, _mesa_CreateShaderProgramEXT); + + /* GL_EXT_gpu_shader4 / GL 3.0 */ + SET_BindFragDataLocationEXT(exec, _mesa_BindFragDataLocation); + SET_GetFragDataLocationEXT(exec, _mesa_GetFragDataLocation); + + /* GL_ARB_ES2_compatibility */ + SET_ReleaseShaderCompiler(exec, _mesa_ReleaseShaderCompiler); + SET_GetShaderPrecisionFormat(exec, _mesa_GetShaderPrecisionFormat); + +#endif /* FEATURE_GL */ +} + diff --git a/mesalib/src/mesa/main/texcompress_s3tc.c b/mesalib/src/mesa/main/texcompress_s3tc.c index 90be6c0a8..86f962e98 100644 --- a/mesalib/src/mesa/main/texcompress_s3tc.c +++ b/mesalib/src/mesa/main/texcompress_s3tc.c @@ -1,574 +1,558 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - * Copyright (c) 2008 VMware, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -/** - * \file texcompress_s3tc.c - * GL_EXT_texture_compression_s3tc support. - */ - -#ifndef USE_EXTERNAL_DXTN_LIB -#define USE_EXTERNAL_DXTN_LIB 1 -#endif - -#include "glheader.h" -#include "imports.h" -#include "colormac.h" -#include "dlopen.h" -#include "image.h" -#include "macros.h" -#include "mfeatures.h" -#include "mtypes.h" -#include "texcompress.h" -#include "texcompress_s3tc.h" -#include "texstore.h" - - -#if FEATURE_texture_s3tc - - -#if defined(_WIN32) || defined(WIN32) -#define DXTN_LIBNAME "dxtn.dll" -#define RTLD_LAZY 0 -#define RTLD_GLOBAL 0 -#elif defined(__DJGPP__) -#define DXTN_LIBNAME "dxtn.dxe" -#else -#define DXTN_LIBNAME "libtxc_dxtn.so" -#endif - -#if FEATURE_EXT_texture_sRGB -/** - * Convert an 8-bit sRGB value from non-linear space to a - * linear RGB value in [0, 1]. - * Implemented with a 256-entry lookup table. - */ -static INLINE GLfloat -nonlinear_to_linear(GLubyte cs8) -{ - static GLfloat table[256]; - static GLboolean tableReady = GL_FALSE; - if (!tableReady) { - /* compute lookup table now */ - GLuint i; - for (i = 0; i < 256; i++) { - const GLfloat cs = UBYTE_TO_FLOAT(i); - if (cs <= 0.04045) { - table[i] = cs / 12.92f; - } - else { - table[i] = (GLfloat) pow((cs + 0.055) / 1.055, 2.4); - } - } - tableReady = GL_TRUE; - } - return table[cs8]; -} -#endif /* FEATURE_EXT_texture_sRGB */ - -typedef void (*dxtFetchTexelFuncExt)( GLint srcRowstride, GLubyte *pixdata, GLint col, GLint row, GLvoid *texelOut ); - -dxtFetchTexelFuncExt fetch_ext_rgb_dxt1 = NULL; -dxtFetchTexelFuncExt fetch_ext_rgba_dxt1 = NULL; -dxtFetchTexelFuncExt fetch_ext_rgba_dxt3 = NULL; -dxtFetchTexelFuncExt fetch_ext_rgba_dxt5 = NULL; - -typedef void (*dxtCompressTexFuncExt)(GLint srccomps, GLint width, - GLint height, const GLchan *srcPixData, - GLenum destformat, GLubyte *dest, - GLint dstRowStride); - -static dxtCompressTexFuncExt ext_tx_compress_dxtn = NULL; - -static void *dxtlibhandle = NULL; - - -void -_mesa_init_texture_s3tc( struct gl_context *ctx ) -{ - /* called during context initialization */ - ctx->Mesa_DXTn = GL_FALSE; -#if USE_EXTERNAL_DXTN_LIB - if (!dxtlibhandle) { - dxtlibhandle = _mesa_dlopen(DXTN_LIBNAME, 0); - if (!dxtlibhandle) { - _mesa_warning(ctx, "couldn't open " DXTN_LIBNAME ", software DXTn " - "compression/decompression unavailable"); - } - else { - /* the fetch functions are not per context! Might be problematic... */ - fetch_ext_rgb_dxt1 = (dxtFetchTexelFuncExt) - _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgb_dxt1"); - fetch_ext_rgba_dxt1 = (dxtFetchTexelFuncExt) - _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgba_dxt1"); - fetch_ext_rgba_dxt3 = (dxtFetchTexelFuncExt) - _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgba_dxt3"); - fetch_ext_rgba_dxt5 = (dxtFetchTexelFuncExt) - _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgba_dxt5"); - ext_tx_compress_dxtn = (dxtCompressTexFuncExt) - _mesa_dlsym(dxtlibhandle, "tx_compress_dxtn"); - - if (!fetch_ext_rgb_dxt1 || - !fetch_ext_rgba_dxt1 || - !fetch_ext_rgba_dxt3 || - !fetch_ext_rgba_dxt5 || - !ext_tx_compress_dxtn) { - _mesa_warning(ctx, "couldn't reference all symbols in " - DXTN_LIBNAME ", software DXTn compression/decompression " - "unavailable"); - fetch_ext_rgb_dxt1 = NULL; - fetch_ext_rgba_dxt1 = NULL; - fetch_ext_rgba_dxt3 = NULL; - fetch_ext_rgba_dxt5 = NULL; - ext_tx_compress_dxtn = NULL; - _mesa_dlclose(dxtlibhandle); - dxtlibhandle = NULL; - } - } - } - if (dxtlibhandle) { - ctx->Mesa_DXTn = GL_TRUE; - } -#else - (void) ctx; -#endif -} - -/** - * Store user's image in rgb_dxt1 format. - */ -GLboolean -_mesa_texstore_rgb_dxt1(TEXSTORE_PARAMS) -{ - const GLchan *pixels; - GLint srcRowStride; - GLubyte *dst; - const GLint texWidth = dstRowStride * 4 / 8; /* a bit of a hack */ - const GLchan *tempImage = NULL; - - ASSERT(dstFormat == MESA_FORMAT_RGB_DXT1 || - dstFormat == MESA_FORMAT_SRGB_DXT1); - ASSERT(dstXoffset % 4 == 0); - ASSERT(dstYoffset % 4 == 0); - ASSERT(dstZoffset % 4 == 0); - (void) dstZoffset; - (void) dstImageOffsets; - - if (srcFormat != GL_RGB || - srcType != CHAN_TYPE || - ctx->_ImageTransferState || - srcPacking->SwapBytes) { - /* convert image to RGB/GLchan */ - tempImage = _mesa_make_temp_chan_image(ctx, dims, - baseInternalFormat, - _mesa_get_format_base_format(dstFormat), - srcWidth, srcHeight, srcDepth, - srcFormat, srcType, srcAddr, - srcPacking); - if (!tempImage) - return GL_FALSE; /* out of memory */ - pixels = tempImage; - srcRowStride = 3 * srcWidth; - srcFormat = GL_RGB; - } - else { - pixels = (const GLchan *) srcAddr; - srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, - srcType) / sizeof(GLchan); - } - - dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0, - dstFormat, - texWidth, (GLubyte *) dstAddr); - - if (ext_tx_compress_dxtn) { - (*ext_tx_compress_dxtn)(3, srcWidth, srcHeight, pixels, - GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - dst, dstRowStride); - } - else { - _mesa_warning(ctx, "external dxt library not available: texstore_rgb_dxt1"); - } - - if (tempImage) - free((void *) tempImage); - - return GL_TRUE; -} - - -/** - * Store user's image in rgba_dxt1 format. - */ -GLboolean -_mesa_texstore_rgba_dxt1(TEXSTORE_PARAMS) -{ - const GLchan *pixels; - GLint srcRowStride; - GLubyte *dst; - const GLint texWidth = dstRowStride * 4 / 8; /* a bit of a hack */ - const GLchan *tempImage = NULL; - - ASSERT(dstFormat == MESA_FORMAT_RGBA_DXT1 || - dstFormat == MESA_FORMAT_SRGBA_DXT1); - ASSERT(dstXoffset % 4 == 0); - ASSERT(dstYoffset % 4 == 0); - ASSERT(dstZoffset % 4 == 0); - (void) dstZoffset; - (void) dstImageOffsets; - - if (srcFormat != GL_RGBA || - srcType != CHAN_TYPE || - ctx->_ImageTransferState || - srcPacking->SwapBytes) { - /* convert image to RGBA/GLchan */ - tempImage = _mesa_make_temp_chan_image(ctx, dims, - baseInternalFormat, - _mesa_get_format_base_format(dstFormat), - srcWidth, srcHeight, srcDepth, - srcFormat, srcType, srcAddr, - srcPacking); - if (!tempImage) - return GL_FALSE; /* out of memory */ - pixels = tempImage; - srcRowStride = 4 * srcWidth; - srcFormat = GL_RGBA; - } - else { - pixels = (const GLchan *) srcAddr; - srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, - srcType) / sizeof(GLchan); - } - - dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0, - dstFormat, - texWidth, (GLubyte *) dstAddr); - if (ext_tx_compress_dxtn) { - (*ext_tx_compress_dxtn)(4, srcWidth, srcHeight, pixels, - GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, - dst, dstRowStride); - } - else { - _mesa_warning(ctx, "external dxt library not available: texstore_rgba_dxt1"); - } - - if (tempImage) - free((void*) tempImage); - - return GL_TRUE; -} - - -/** - * Store user's image in rgba_dxt3 format. - */ -GLboolean -_mesa_texstore_rgba_dxt3(TEXSTORE_PARAMS) -{ - const GLchan *pixels; - GLint srcRowStride; - GLubyte *dst; - const GLint texWidth = dstRowStride * 4 / 16; /* a bit of a hack */ - const GLchan *tempImage = NULL; - - ASSERT(dstFormat == MESA_FORMAT_RGBA_DXT3 || - dstFormat == MESA_FORMAT_SRGBA_DXT3); - ASSERT(dstXoffset % 4 == 0); - ASSERT(dstYoffset % 4 == 0); - ASSERT(dstZoffset % 4 == 0); - (void) dstZoffset; - (void) dstImageOffsets; - - if (srcFormat != GL_RGBA || - srcType != CHAN_TYPE || - ctx->_ImageTransferState || - srcPacking->SwapBytes) { - /* convert image to RGBA/GLchan */ - tempImage = _mesa_make_temp_chan_image(ctx, dims, - baseInternalFormat, - _mesa_get_format_base_format(dstFormat), - srcWidth, srcHeight, srcDepth, - srcFormat, srcType, srcAddr, - srcPacking); - if (!tempImage) - return GL_FALSE; /* out of memory */ - pixels = tempImage; - srcRowStride = 4 * srcWidth; - } - else { - pixels = (const GLchan *) srcAddr; - srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, - srcType) / sizeof(GLchan); - } - - dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0, - dstFormat, - texWidth, (GLubyte *) dstAddr); - if (ext_tx_compress_dxtn) { - (*ext_tx_compress_dxtn)(4, srcWidth, srcHeight, pixels, - GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, - dst, dstRowStride); - } - else { - _mesa_warning(ctx, "external dxt library not available: texstore_rgba_dxt3"); - } - - if (tempImage) - free((void *) tempImage); - - return GL_TRUE; -} - - -/** - * Store user's image in rgba_dxt5 format. - */ -GLboolean -_mesa_texstore_rgba_dxt5(TEXSTORE_PARAMS) -{ - const GLchan *pixels; - GLint srcRowStride; - GLubyte *dst; - const GLint texWidth = dstRowStride * 4 / 16; /* a bit of a hack */ - const GLchan *tempImage = NULL; - - ASSERT(dstFormat == MESA_FORMAT_RGBA_DXT5 || - dstFormat == MESA_FORMAT_SRGBA_DXT5); - ASSERT(dstXoffset % 4 == 0); - ASSERT(dstYoffset % 4 == 0); - ASSERT(dstZoffset % 4 == 0); - (void) dstZoffset; - (void) dstImageOffsets; - - if (srcFormat != GL_RGBA || - srcType != CHAN_TYPE || - ctx->_ImageTransferState || - srcPacking->SwapBytes) { - /* convert image to RGBA/GLchan */ - tempImage = _mesa_make_temp_chan_image(ctx, dims, - baseInternalFormat, - _mesa_get_format_base_format(dstFormat), - srcWidth, srcHeight, srcDepth, - srcFormat, srcType, srcAddr, - srcPacking); - if (!tempImage) - return GL_FALSE; /* out of memory */ - pixels = tempImage; - srcRowStride = 4 * srcWidth; - } - else { - pixels = (const GLchan *) srcAddr; - srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, - srcType) / sizeof(GLchan); - } - - dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0, - dstFormat, - texWidth, (GLubyte *) dstAddr); - if (ext_tx_compress_dxtn) { - (*ext_tx_compress_dxtn)(4, srcWidth, srcHeight, pixels, - GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, - dst, dstRowStride); - } - else { - _mesa_warning(ctx, "external dxt library not available: texstore_rgba_dxt5"); - } - - if (tempImage) - free((void *) tempImage); - - return GL_TRUE; -} - - -static void -fetch_texel_2d_rgb_dxt1( const struct gl_texture_image *texImage, - GLint i, GLint j, GLint k, GLchan *texel ) -{ - (void) k; - if (fetch_ext_rgb_dxt1) { - ASSERT (sizeof(GLchan) == sizeof(GLubyte)); - fetch_ext_rgb_dxt1(texImage->RowStride, - (GLubyte *)(texImage)->Data, i, j, texel); - } - else - _mesa_debug(NULL, "attempted to decode s3tc texture without library available: fetch_texel_2d_rgb_dxt1"); -} - - -void -_mesa_fetch_texel_2d_f_rgb_dxt1(const struct gl_texture_image *texImage, - GLint i, GLint j, GLint k, GLfloat *texel) -{ - /* just sample as GLchan and convert to float here */ - GLchan rgba[4]; - fetch_texel_2d_rgb_dxt1(texImage, i, j, k, rgba); - texel[RCOMP] = CHAN_TO_FLOAT(rgba[RCOMP]); - texel[GCOMP] = CHAN_TO_FLOAT(rgba[GCOMP]); - texel[BCOMP] = CHAN_TO_FLOAT(rgba[BCOMP]); - texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); -} - - -static void -fetch_texel_2d_rgba_dxt1( const struct gl_texture_image *texImage, - GLint i, GLint j, GLint k, GLchan *texel ) -{ - (void) k; - if (fetch_ext_rgba_dxt1) { - fetch_ext_rgba_dxt1(texImage->RowStride, - (GLubyte *)(texImage)->Data, i, j, texel); - } - else - _mesa_debug(NULL, "attempted to decode s3tc texture without library available: fetch_texel_2d_rgba_dxt1\n"); -} - - -void -_mesa_fetch_texel_2d_f_rgba_dxt1(const struct gl_texture_image *texImage, - GLint i, GLint j, GLint k, GLfloat *texel) -{ - /* just sample as GLchan and convert to float here */ - GLchan rgba[4]; - fetch_texel_2d_rgba_dxt1(texImage, i, j, k, rgba); - texel[RCOMP] = CHAN_TO_FLOAT(rgba[RCOMP]); - texel[GCOMP] = CHAN_TO_FLOAT(rgba[GCOMP]); - texel[BCOMP] = CHAN_TO_FLOAT(rgba[BCOMP]); - texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); -} - - -static void -fetch_texel_2d_rgba_dxt3( const struct gl_texture_image *texImage, - GLint i, GLint j, GLint k, GLchan *texel ) -{ - (void) k; - if (fetch_ext_rgba_dxt3) { - ASSERT (sizeof(GLchan) == sizeof(GLubyte)); - fetch_ext_rgba_dxt3(texImage->RowStride, (GLubyte *)(texImage)->Data, - i, j, texel); - } - else - _mesa_debug(NULL, "attempted to decode s3tc texture without library available: fetch_texel_2d_rgba_dxt3\n"); -} - - -void -_mesa_fetch_texel_2d_f_rgba_dxt3(const struct gl_texture_image *texImage, - GLint i, GLint j, GLint k, GLfloat *texel) -{ - /* just sample as GLchan and convert to float here */ - GLchan rgba[4]; - fetch_texel_2d_rgba_dxt3(texImage, i, j, k, rgba); - texel[RCOMP] = CHAN_TO_FLOAT(rgba[RCOMP]); - texel[GCOMP] = CHAN_TO_FLOAT(rgba[GCOMP]); - texel[BCOMP] = CHAN_TO_FLOAT(rgba[BCOMP]); - texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); -} - - -static void -fetch_texel_2d_rgba_dxt5( const struct gl_texture_image *texImage, - GLint i, GLint j, GLint k, GLchan *texel ) -{ - (void) k; - if (fetch_ext_rgba_dxt5) { - fetch_ext_rgba_dxt5(texImage->RowStride, (GLubyte *)(texImage)->Data, - i, j, texel); - } - else - _mesa_debug(NULL, "attempted to decode s3tc texture without library available: fetch_texel_2d_rgba_dxt5\n"); -} - - -void -_mesa_fetch_texel_2d_f_rgba_dxt5(const struct gl_texture_image *texImage, - GLint i, GLint j, GLint k, GLfloat *texel) -{ - /* just sample as GLchan and convert to float here */ - GLchan rgba[4]; - fetch_texel_2d_rgba_dxt5(texImage, i, j, k, rgba); - texel[RCOMP] = CHAN_TO_FLOAT(rgba[RCOMP]); - texel[GCOMP] = CHAN_TO_FLOAT(rgba[GCOMP]); - texel[BCOMP] = CHAN_TO_FLOAT(rgba[BCOMP]); - texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); -} - -#if FEATURE_EXT_texture_sRGB -void -_mesa_fetch_texel_2d_f_srgb_dxt1( const struct gl_texture_image *texImage, - GLint i, GLint j, GLint k, GLfloat *texel ) -{ - /* just sample as GLchan and convert to float here */ - GLchan rgba[4]; - fetch_texel_2d_rgb_dxt1(texImage, i, j, k, rgba); - texel[RCOMP] = nonlinear_to_linear(rgba[RCOMP]); - texel[GCOMP] = nonlinear_to_linear(rgba[GCOMP]); - texel[BCOMP] = nonlinear_to_linear(rgba[BCOMP]); - texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); -} - -void -_mesa_fetch_texel_2d_f_srgba_dxt1(const struct gl_texture_image *texImage, - GLint i, GLint j, GLint k, GLfloat *texel) -{ - /* just sample as GLchan and convert to float here */ - GLchan rgba[4]; - fetch_texel_2d_rgba_dxt1(texImage, i, j, k, rgba); - texel[RCOMP] = nonlinear_to_linear(rgba[RCOMP]); - texel[GCOMP] = nonlinear_to_linear(rgba[GCOMP]); - texel[BCOMP] = nonlinear_to_linear(rgba[BCOMP]); - texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); -} - -void -_mesa_fetch_texel_2d_f_srgba_dxt3(const struct gl_texture_image *texImage, - GLint i, GLint j, GLint k, GLfloat *texel) -{ - /* just sample as GLchan and convert to float here */ - GLchan rgba[4]; - fetch_texel_2d_rgba_dxt3(texImage, i, j, k, rgba); - texel[RCOMP] = nonlinear_to_linear(rgba[RCOMP]); - texel[GCOMP] = nonlinear_to_linear(rgba[GCOMP]); - texel[BCOMP] = nonlinear_to_linear(rgba[BCOMP]); - texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); -} - -void -_mesa_fetch_texel_2d_f_srgba_dxt5(const struct gl_texture_image *texImage, - GLint i, GLint j, GLint k, GLfloat *texel) -{ - /* just sample as GLchan and convert to float here */ - GLchan rgba[4]; - fetch_texel_2d_rgba_dxt5(texImage, i, j, k, rgba); - texel[RCOMP] = nonlinear_to_linear(rgba[RCOMP]); - texel[GCOMP] = nonlinear_to_linear(rgba[GCOMP]); - texel[BCOMP] = nonlinear_to_linear(rgba[BCOMP]); - texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); -} -#endif /* FEATURE_EXT_texture_sRGB */ - - -#endif /* FEATURE_texture_s3tc */ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * Copyright (c) 2008 VMware, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** + * \file texcompress_s3tc.c + * GL_EXT_texture_compression_s3tc support. + */ + +#ifndef USE_EXTERNAL_DXTN_LIB +#define USE_EXTERNAL_DXTN_LIB 1 +#endif + +#include "glheader.h" +#include "imports.h" +#include "colormac.h" +#include "dlopen.h" +#include "image.h" +#include "macros.h" +#include "mfeatures.h" +#include "mtypes.h" +#include "texcompress.h" +#include "texcompress_s3tc.h" +#include "texstore.h" + + +#if FEATURE_texture_s3tc + + +#if defined(_WIN32) || defined(WIN32) +#define DXTN_LIBNAME "dxtn.dll" +#define RTLD_LAZY 0 +#define RTLD_GLOBAL 0 +#elif defined(__DJGPP__) +#define DXTN_LIBNAME "dxtn.dxe" +#else +#define DXTN_LIBNAME "libtxc_dxtn.so" +#endif + +#if FEATURE_EXT_texture_sRGB +/** + * Convert an 8-bit sRGB value from non-linear space to a + * linear RGB value in [0, 1]. + * Implemented with a 256-entry lookup table. + */ +static INLINE GLfloat +nonlinear_to_linear(GLubyte cs8) +{ + static GLfloat table[256]; + static GLboolean tableReady = GL_FALSE; + if (!tableReady) { + /* compute lookup table now */ + GLuint i; + for (i = 0; i < 256; i++) { + const GLfloat cs = UBYTE_TO_FLOAT(i); + if (cs <= 0.04045) { + table[i] = cs / 12.92f; + } + else { + table[i] = (GLfloat) pow((cs + 0.055) / 1.055, 2.4); + } + } + tableReady = GL_TRUE; + } + return table[cs8]; +} +#endif /* FEATURE_EXT_texture_sRGB */ + +typedef void (*dxtFetchTexelFuncExt)( GLint srcRowstride, GLubyte *pixdata, GLint col, GLint row, GLvoid *texelOut ); + +dxtFetchTexelFuncExt fetch_ext_rgb_dxt1 = NULL; +dxtFetchTexelFuncExt fetch_ext_rgba_dxt1 = NULL; +dxtFetchTexelFuncExt fetch_ext_rgba_dxt3 = NULL; +dxtFetchTexelFuncExt fetch_ext_rgba_dxt5 = NULL; + +typedef void (*dxtCompressTexFuncExt)(GLint srccomps, GLint width, + GLint height, const GLchan *srcPixData, + GLenum destformat, GLubyte *dest, + GLint dstRowStride); + +static dxtCompressTexFuncExt ext_tx_compress_dxtn = NULL; + +static void *dxtlibhandle = NULL; + + +void +_mesa_init_texture_s3tc( struct gl_context *ctx ) +{ + /* called during context initialization */ + ctx->Mesa_DXTn = GL_FALSE; +#if USE_EXTERNAL_DXTN_LIB + if (!dxtlibhandle) { + dxtlibhandle = _mesa_dlopen(DXTN_LIBNAME, 0); + if (!dxtlibhandle) { + _mesa_warning(ctx, "couldn't open " DXTN_LIBNAME ", software DXTn " + "compression/decompression unavailable"); + } + else { + /* the fetch functions are not per context! Might be problematic... */ + fetch_ext_rgb_dxt1 = (dxtFetchTexelFuncExt) + _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgb_dxt1"); + fetch_ext_rgba_dxt1 = (dxtFetchTexelFuncExt) + _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgba_dxt1"); + fetch_ext_rgba_dxt3 = (dxtFetchTexelFuncExt) + _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgba_dxt3"); + fetch_ext_rgba_dxt5 = (dxtFetchTexelFuncExt) + _mesa_dlsym(dxtlibhandle, "fetch_2d_texel_rgba_dxt5"); + ext_tx_compress_dxtn = (dxtCompressTexFuncExt) + _mesa_dlsym(dxtlibhandle, "tx_compress_dxtn"); + + if (!fetch_ext_rgb_dxt1 || + !fetch_ext_rgba_dxt1 || + !fetch_ext_rgba_dxt3 || + !fetch_ext_rgba_dxt5 || + !ext_tx_compress_dxtn) { + _mesa_warning(ctx, "couldn't reference all symbols in " + DXTN_LIBNAME ", software DXTn compression/decompression " + "unavailable"); + fetch_ext_rgb_dxt1 = NULL; + fetch_ext_rgba_dxt1 = NULL; + fetch_ext_rgba_dxt3 = NULL; + fetch_ext_rgba_dxt5 = NULL; + ext_tx_compress_dxtn = NULL; + _mesa_dlclose(dxtlibhandle); + dxtlibhandle = NULL; + } + } + } + if (dxtlibhandle) { + ctx->Mesa_DXTn = GL_TRUE; + } +#else + (void) ctx; +#endif +} + +/** + * Store user's image in rgb_dxt1 format. + */ +GLboolean +_mesa_texstore_rgb_dxt1(TEXSTORE_PARAMS) +{ + const GLchan *pixels; + GLubyte *dst; + const GLint texWidth = dstRowStride * 4 / 8; /* a bit of a hack */ + const GLchan *tempImage = NULL; + + ASSERT(dstFormat == MESA_FORMAT_RGB_DXT1 || + dstFormat == MESA_FORMAT_SRGB_DXT1); + ASSERT(dstXoffset % 4 == 0); + ASSERT(dstYoffset % 4 == 0); + ASSERT(dstZoffset % 4 == 0); + (void) dstZoffset; + (void) dstImageOffsets; + + if (srcFormat != GL_RGB || + srcType != CHAN_TYPE || + ctx->_ImageTransferState || + srcPacking->SwapBytes) { + /* convert image to RGB/GLchan */ + tempImage = _mesa_make_temp_chan_image(ctx, dims, + baseInternalFormat, + _mesa_get_format_base_format(dstFormat), + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, srcAddr, + srcPacking); + if (!tempImage) + return GL_FALSE; /* out of memory */ + pixels = tempImage; + srcFormat = GL_RGB; + } + else { + pixels = (const GLchan *) srcAddr; + } + + dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0, + dstFormat, + texWidth, (GLubyte *) dstAddr); + + if (ext_tx_compress_dxtn) { + (*ext_tx_compress_dxtn)(3, srcWidth, srcHeight, pixels, + GL_COMPRESSED_RGB_S3TC_DXT1_EXT, + dst, dstRowStride); + } + else { + _mesa_warning(ctx, "external dxt library not available: texstore_rgb_dxt1"); + } + + if (tempImage) + free((void *) tempImage); + + return GL_TRUE; +} + + +/** + * Store user's image in rgba_dxt1 format. + */ +GLboolean +_mesa_texstore_rgba_dxt1(TEXSTORE_PARAMS) +{ + const GLchan *pixels; + GLubyte *dst; + const GLint texWidth = dstRowStride * 4 / 8; /* a bit of a hack */ + const GLchan *tempImage = NULL; + + ASSERT(dstFormat == MESA_FORMAT_RGBA_DXT1 || + dstFormat == MESA_FORMAT_SRGBA_DXT1); + ASSERT(dstXoffset % 4 == 0); + ASSERT(dstYoffset % 4 == 0); + ASSERT(dstZoffset % 4 == 0); + (void) dstZoffset; + (void) dstImageOffsets; + + if (srcFormat != GL_RGBA || + srcType != CHAN_TYPE || + ctx->_ImageTransferState || + srcPacking->SwapBytes) { + /* convert image to RGBA/GLchan */ + tempImage = _mesa_make_temp_chan_image(ctx, dims, + baseInternalFormat, + _mesa_get_format_base_format(dstFormat), + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, srcAddr, + srcPacking); + if (!tempImage) + return GL_FALSE; /* out of memory */ + pixels = tempImage; + srcFormat = GL_RGBA; + } + else { + pixels = (const GLchan *) srcAddr; + } + + dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0, + dstFormat, + texWidth, (GLubyte *) dstAddr); + if (ext_tx_compress_dxtn) { + (*ext_tx_compress_dxtn)(4, srcWidth, srcHeight, pixels, + GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, + dst, dstRowStride); + } + else { + _mesa_warning(ctx, "external dxt library not available: texstore_rgba_dxt1"); + } + + if (tempImage) + free((void*) tempImage); + + return GL_TRUE; +} + + +/** + * Store user's image in rgba_dxt3 format. + */ +GLboolean +_mesa_texstore_rgba_dxt3(TEXSTORE_PARAMS) +{ + const GLchan *pixels; + GLubyte *dst; + const GLint texWidth = dstRowStride * 4 / 16; /* a bit of a hack */ + const GLchan *tempImage = NULL; + + ASSERT(dstFormat == MESA_FORMAT_RGBA_DXT3 || + dstFormat == MESA_FORMAT_SRGBA_DXT3); + ASSERT(dstXoffset % 4 == 0); + ASSERT(dstYoffset % 4 == 0); + ASSERT(dstZoffset % 4 == 0); + (void) dstZoffset; + (void) dstImageOffsets; + + if (srcFormat != GL_RGBA || + srcType != CHAN_TYPE || + ctx->_ImageTransferState || + srcPacking->SwapBytes) { + /* convert image to RGBA/GLchan */ + tempImage = _mesa_make_temp_chan_image(ctx, dims, + baseInternalFormat, + _mesa_get_format_base_format(dstFormat), + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, srcAddr, + srcPacking); + if (!tempImage) + return GL_FALSE; /* out of memory */ + pixels = tempImage; + } + else { + pixels = (const GLchan *) srcAddr; + } + + dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0, + dstFormat, + texWidth, (GLubyte *) dstAddr); + if (ext_tx_compress_dxtn) { + (*ext_tx_compress_dxtn)(4, srcWidth, srcHeight, pixels, + GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, + dst, dstRowStride); + } + else { + _mesa_warning(ctx, "external dxt library not available: texstore_rgba_dxt3"); + } + + if (tempImage) + free((void *) tempImage); + + return GL_TRUE; +} + + +/** + * Store user's image in rgba_dxt5 format. + */ +GLboolean +_mesa_texstore_rgba_dxt5(TEXSTORE_PARAMS) +{ + const GLchan *pixels; + GLubyte *dst; + const GLint texWidth = dstRowStride * 4 / 16; /* a bit of a hack */ + const GLchan *tempImage = NULL; + + ASSERT(dstFormat == MESA_FORMAT_RGBA_DXT5 || + dstFormat == MESA_FORMAT_SRGBA_DXT5); + ASSERT(dstXoffset % 4 == 0); + ASSERT(dstYoffset % 4 == 0); + ASSERT(dstZoffset % 4 == 0); + (void) dstZoffset; + (void) dstImageOffsets; + + if (srcFormat != GL_RGBA || + srcType != CHAN_TYPE || + ctx->_ImageTransferState || + srcPacking->SwapBytes) { + /* convert image to RGBA/GLchan */ + tempImage = _mesa_make_temp_chan_image(ctx, dims, + baseInternalFormat, + _mesa_get_format_base_format(dstFormat), + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, srcAddr, + srcPacking); + if (!tempImage) + return GL_FALSE; /* out of memory */ + pixels = tempImage; + } + else { + pixels = (const GLchan *) srcAddr; + } + + dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0, + dstFormat, + texWidth, (GLubyte *) dstAddr); + if (ext_tx_compress_dxtn) { + (*ext_tx_compress_dxtn)(4, srcWidth, srcHeight, pixels, + GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, + dst, dstRowStride); + } + else { + _mesa_warning(ctx, "external dxt library not available: texstore_rgba_dxt5"); + } + + if (tempImage) + free((void *) tempImage); + + return GL_TRUE; +} + + +static void +fetch_texel_2d_rgb_dxt1( const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLchan *texel ) +{ + (void) k; + if (fetch_ext_rgb_dxt1) { + ASSERT (sizeof(GLchan) == sizeof(GLubyte)); + fetch_ext_rgb_dxt1(texImage->RowStride, + (GLubyte *)(texImage)->Data, i, j, texel); + } + else + _mesa_debug(NULL, "attempted to decode s3tc texture without library available: fetch_texel_2d_rgb_dxt1"); +} + + +void +_mesa_fetch_texel_2d_f_rgb_dxt1(const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLfloat *texel) +{ + /* just sample as GLchan and convert to float here */ + GLchan rgba[4]; + fetch_texel_2d_rgb_dxt1(texImage, i, j, k, rgba); + texel[RCOMP] = CHAN_TO_FLOAT(rgba[RCOMP]); + texel[GCOMP] = CHAN_TO_FLOAT(rgba[GCOMP]); + texel[BCOMP] = CHAN_TO_FLOAT(rgba[BCOMP]); + texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); +} + + +static void +fetch_texel_2d_rgba_dxt1( const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLchan *texel ) +{ + (void) k; + if (fetch_ext_rgba_dxt1) { + fetch_ext_rgba_dxt1(texImage->RowStride, + (GLubyte *)(texImage)->Data, i, j, texel); + } + else + _mesa_debug(NULL, "attempted to decode s3tc texture without library available: fetch_texel_2d_rgba_dxt1\n"); +} + + +void +_mesa_fetch_texel_2d_f_rgba_dxt1(const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLfloat *texel) +{ + /* just sample as GLchan and convert to float here */ + GLchan rgba[4]; + fetch_texel_2d_rgba_dxt1(texImage, i, j, k, rgba); + texel[RCOMP] = CHAN_TO_FLOAT(rgba[RCOMP]); + texel[GCOMP] = CHAN_TO_FLOAT(rgba[GCOMP]); + texel[BCOMP] = CHAN_TO_FLOAT(rgba[BCOMP]); + texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); +} + + +static void +fetch_texel_2d_rgba_dxt3( const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLchan *texel ) +{ + (void) k; + if (fetch_ext_rgba_dxt3) { + ASSERT (sizeof(GLchan) == sizeof(GLubyte)); + fetch_ext_rgba_dxt3(texImage->RowStride, (GLubyte *)(texImage)->Data, + i, j, texel); + } + else + _mesa_debug(NULL, "attempted to decode s3tc texture without library available: fetch_texel_2d_rgba_dxt3\n"); +} + + +void +_mesa_fetch_texel_2d_f_rgba_dxt3(const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLfloat *texel) +{ + /* just sample as GLchan and convert to float here */ + GLchan rgba[4]; + fetch_texel_2d_rgba_dxt3(texImage, i, j, k, rgba); + texel[RCOMP] = CHAN_TO_FLOAT(rgba[RCOMP]); + texel[GCOMP] = CHAN_TO_FLOAT(rgba[GCOMP]); + texel[BCOMP] = CHAN_TO_FLOAT(rgba[BCOMP]); + texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); +} + + +static void +fetch_texel_2d_rgba_dxt5( const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLchan *texel ) +{ + (void) k; + if (fetch_ext_rgba_dxt5) { + fetch_ext_rgba_dxt5(texImage->RowStride, (GLubyte *)(texImage)->Data, + i, j, texel); + } + else + _mesa_debug(NULL, "attempted to decode s3tc texture without library available: fetch_texel_2d_rgba_dxt5\n"); +} + + +void +_mesa_fetch_texel_2d_f_rgba_dxt5(const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLfloat *texel) +{ + /* just sample as GLchan and convert to float here */ + GLchan rgba[4]; + fetch_texel_2d_rgba_dxt5(texImage, i, j, k, rgba); + texel[RCOMP] = CHAN_TO_FLOAT(rgba[RCOMP]); + texel[GCOMP] = CHAN_TO_FLOAT(rgba[GCOMP]); + texel[BCOMP] = CHAN_TO_FLOAT(rgba[BCOMP]); + texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); +} + +#if FEATURE_EXT_texture_sRGB +void +_mesa_fetch_texel_2d_f_srgb_dxt1( const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLfloat *texel ) +{ + /* just sample as GLchan and convert to float here */ + GLchan rgba[4]; + fetch_texel_2d_rgb_dxt1(texImage, i, j, k, rgba); + texel[RCOMP] = nonlinear_to_linear(rgba[RCOMP]); + texel[GCOMP] = nonlinear_to_linear(rgba[GCOMP]); + texel[BCOMP] = nonlinear_to_linear(rgba[BCOMP]); + texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); +} + +void +_mesa_fetch_texel_2d_f_srgba_dxt1(const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLfloat *texel) +{ + /* just sample as GLchan and convert to float here */ + GLchan rgba[4]; + fetch_texel_2d_rgba_dxt1(texImage, i, j, k, rgba); + texel[RCOMP] = nonlinear_to_linear(rgba[RCOMP]); + texel[GCOMP] = nonlinear_to_linear(rgba[GCOMP]); + texel[BCOMP] = nonlinear_to_linear(rgba[BCOMP]); + texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); +} + +void +_mesa_fetch_texel_2d_f_srgba_dxt3(const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLfloat *texel) +{ + /* just sample as GLchan and convert to float here */ + GLchan rgba[4]; + fetch_texel_2d_rgba_dxt3(texImage, i, j, k, rgba); + texel[RCOMP] = nonlinear_to_linear(rgba[RCOMP]); + texel[GCOMP] = nonlinear_to_linear(rgba[GCOMP]); + texel[BCOMP] = nonlinear_to_linear(rgba[BCOMP]); + texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); +} + +void +_mesa_fetch_texel_2d_f_srgba_dxt5(const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLfloat *texel) +{ + /* just sample as GLchan and convert to float here */ + GLchan rgba[4]; + fetch_texel_2d_rgba_dxt5(texImage, i, j, k, rgba); + texel[RCOMP] = nonlinear_to_linear(rgba[RCOMP]); + texel[GCOMP] = nonlinear_to_linear(rgba[GCOMP]); + texel[BCOMP] = nonlinear_to_linear(rgba[BCOMP]); + texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); +} +#endif /* FEATURE_EXT_texture_sRGB */ + + +#endif /* FEATURE_texture_s3tc */ diff --git a/mesalib/src/mesa/program/ir_to_mesa.cpp b/mesalib/src/mesa/program/ir_to_mesa.cpp index 3c9b97338..bc10b455b 100644 --- a/mesalib/src/mesa/program/ir_to_mesa.cpp +++ b/mesalib/src/mesa/program/ir_to_mesa.cpp @@ -1481,7 +1481,6 @@ ir_to_mesa_visitor::visit(ir_dereference_array *ir) if (index) { src.index += index->value.i[0] * element_size; } else { - src_reg array_base = this->result; /* Variable index array dereference. It eats the "vec4" of the * base of the array and an index that offsets the Mesa register * index. @@ -2163,7 +2162,7 @@ ir_to_mesa_visitor::visit(ir_discard *ir) void ir_to_mesa_visitor::visit(ir_if *ir) { - ir_to_mesa_instruction *cond_inst, *if_inst, *else_inst = NULL; + ir_to_mesa_instruction *cond_inst, *if_inst; ir_to_mesa_instruction *prev_inst; prev_inst = (ir_to_mesa_instruction *)this->instructions.get_tail(); @@ -2195,7 +2194,7 @@ ir_to_mesa_visitor::visit(ir_if *ir) visit_exec_list(&ir->then_instructions, this); if (!ir->else_instructions.is_empty()) { - else_inst = emit(ir->condition, OPCODE_ELSE); + emit(ir->condition, OPCODE_ELSE); visit_exec_list(&ir->else_instructions, this); } diff --git a/mesalib/src/mesa/program/register_allocate.c b/mesalib/src/mesa/program/register_allocate.c index e78db24a4..de96eb42c 100644 --- a/mesalib/src/mesa/program/register_allocate.c +++ b/mesalib/src/mesa/program/register_allocate.c @@ -1,517 +1,537 @@ -/* - * Copyright © 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Eric Anholt - * - */ - -/** @file register_allocate.c - * - * Graph-coloring register allocator. - * - * The basic idea of graph coloring is to make a node in a graph for - * every thing that needs a register (color) number assigned, and make - * edges in the graph between nodes that interfere (can't be allocated - * to the same register at the same time). - * - * During the "simplify" process, any any node with fewer edges than - * there are registers means that that edge can get assigned a - * register regardless of what its neighbors choose, so that node is - * pushed on a stack and removed (with its edges) from the graph. - * That likely causes other nodes to become trivially colorable as well. - * - * Then during the "select" process, nodes are popped off of that - * stack, their edges restored, and assigned a color different from - * their neighbors. Because they were pushed on the stack only when - * they were trivially colorable, any color chosen won't interfere - * with the registers to be popped later. - * - * The downside to most graph coloring is that real hardware often has - * limitations, like registers that need to be allocated to a node in - * pairs, or aligned on some boundary. This implementation follows - * the paper "Retargetable Graph-Coloring Register Allocation for - * Irregular Architectures" by Johan Runeson and Sven-Olof Nyström. - * - * In this system, there are register classes each containing various - * registers, and registers may interfere with other registers. For - * example, one might have a class of base registers, and a class of - * aligned register pairs that would each interfere with their pair of - * the base registers. Each node has a register class it needs to be - * assigned to. Define p(B) to be the size of register class B, and - * q(B,C) to be the number of registers in B that the worst choice - * register in C could conflict with. Then, this system replaces the - * basic graph coloring test of "fewer edges from this node than there - * are registers" with "For this node of class B, the sum of q(B,C) - * for each neighbor node of class C is less than pB". - * - * A nice feature of the pq test is that q(B,C) can be computed once - * up front and stored in a 2-dimensional array, so that the cost of - * coloring a node is constant with the number of registers. We do - * this during ra_set_finalize(). - */ - -#include - -#include "main/imports.h" -#include "main/macros.h" -#include "main/mtypes.h" -#include "register_allocate.h" - -struct ra_reg { - GLboolean *conflicts; - unsigned int *conflict_list; - unsigned int conflict_list_size; - unsigned int num_conflicts; -}; - -struct ra_regs { - struct ra_reg *regs; - unsigned int count; - - struct ra_class **classes; - unsigned int class_count; -}; - -struct ra_class { - GLboolean *regs; - - /** - * p(B) in Runeson/Nyström paper. - * - * This is "how many regs are in the set." - */ - unsigned int p; - - /** - * q(B,C) (indexed by C, B is this register class) in - * Runeson/Nyström paper. This is "how many registers of B could - * the worst choice register from C conflict with". - */ - unsigned int *q; -}; - -struct ra_node { - /** @{ - * - * List of which nodes this node interferes with. This should be - * symmetric with the other node. - */ - GLboolean *adjacency; - unsigned int *adjacency_list; - unsigned int adjacency_count; - /** @} */ - - unsigned int class; - - /* Register, if assigned, or ~0. */ - unsigned int reg; - - /** - * Set when the node is in the trivially colorable stack. When - * set, the adjacency to this node is ignored, to implement the - * "remove the edge from the graph" in simplification without - * having to actually modify the adjacency_list. - */ - GLboolean in_stack; - - /* For an implementation that needs register spilling, this is the - * approximate cost of spilling this node. - */ - float spill_cost; -}; - -struct ra_graph { - struct ra_regs *regs; - /** - * the variables that need register allocation. - */ - struct ra_node *nodes; - unsigned int count; /**< count of nodes. */ - - unsigned int *stack; - unsigned int stack_count; -}; - -struct ra_regs * -ra_alloc_reg_set(unsigned int count) -{ - unsigned int i; - struct ra_regs *regs; - - regs = rzalloc(NULL, struct ra_regs); - regs->count = count; - regs->regs = rzalloc_array(regs, struct ra_reg, count); - - for (i = 0; i < count; i++) { - regs->regs[i].conflicts = rzalloc_array(regs->regs, GLboolean, count); - regs->regs[i].conflicts[i] = GL_TRUE; - - regs->regs[i].conflict_list = ralloc_array(regs->regs, unsigned int, 4); - regs->regs[i].conflict_list_size = 4; - regs->regs[i].conflict_list[0] = i; - regs->regs[i].num_conflicts = 1; - } - - return regs; -} - -static void -ra_add_conflict_list(struct ra_regs *regs, unsigned int r1, unsigned int r2) -{ - struct ra_reg *reg1 = ®s->regs[r1]; - - if (reg1->conflict_list_size == reg1->num_conflicts) { - reg1->conflict_list_size *= 2; - reg1->conflict_list = reralloc(regs->regs, reg1->conflict_list, - unsigned int, reg1->conflict_list_size); - } - reg1->conflict_list[reg1->num_conflicts++] = r2; - reg1->conflicts[r2] = GL_TRUE; -} - -void -ra_add_reg_conflict(struct ra_regs *regs, unsigned int r1, unsigned int r2) -{ - if (!regs->regs[r1].conflicts[r2]) { - ra_add_conflict_list(regs, r1, r2); - ra_add_conflict_list(regs, r2, r1); - } -} - -unsigned int -ra_alloc_reg_class(struct ra_regs *regs) -{ - struct ra_class *class; - - regs->classes = reralloc(regs->regs, regs->classes, struct ra_class *, - regs->class_count + 1); - - class = rzalloc(regs, struct ra_class); - regs->classes[regs->class_count] = class; - - class->regs = rzalloc_array(class, GLboolean, regs->count); - - return regs->class_count++; -} - -void -ra_class_add_reg(struct ra_regs *regs, unsigned int c, unsigned int r) -{ - struct ra_class *class = regs->classes[c]; - - class->regs[r] = GL_TRUE; - class->p++; -} - -/** - * Must be called after all conflicts and register classes have been - * set up and before the register set is used for allocation. - */ -void -ra_set_finalize(struct ra_regs *regs) -{ - unsigned int b, c; - - for (b = 0; b < regs->class_count; b++) { - regs->classes[b]->q = ralloc_array(regs, unsigned int, regs->class_count); - } - - /* Compute, for each class B and C, how many regs of B an - * allocation to C could conflict with. - */ - for (b = 0; b < regs->class_count; b++) { - for (c = 0; c < regs->class_count; c++) { - unsigned int rc; - int max_conflicts = 0; - - for (rc = 0; rc < regs->count; rc++) { - int conflicts = 0; - int i; - - if (!regs->classes[c]->regs[rc]) - continue; - - for (i = 0; i < regs->regs[rc].num_conflicts; i++) { - unsigned int rb = regs->regs[rc].conflict_list[i]; - if (regs->classes[b]->regs[rb]) - conflicts++; - } - max_conflicts = MAX2(max_conflicts, conflicts); - } - regs->classes[b]->q[c] = max_conflicts; - } - } -} - -static void -ra_add_node_adjacency(struct ra_graph *g, unsigned int n1, unsigned int n2) -{ - g->nodes[n1].adjacency[n2] = GL_TRUE; - g->nodes[n1].adjacency_list[g->nodes[n1].adjacency_count] = n2; - g->nodes[n1].adjacency_count++; -} - -struct ra_graph * -ra_alloc_interference_graph(struct ra_regs *regs, unsigned int count) -{ - struct ra_graph *g; - unsigned int i; - - g = rzalloc(regs, struct ra_graph); - g->regs = regs; - g->nodes = rzalloc_array(g, struct ra_node, count); - g->count = count; - - g->stack = rzalloc_array(g, unsigned int, count); - - for (i = 0; i < count; i++) { - g->nodes[i].adjacency = rzalloc_array(g, GLboolean, count); - g->nodes[i].adjacency_list = ralloc_array(g, unsigned int, count); - g->nodes[i].adjacency_count = 0; - ra_add_node_adjacency(g, i, i); - g->nodes[i].reg = ~0; - } - - return g; -} - -void -ra_set_node_class(struct ra_graph *g, - unsigned int n, unsigned int class) -{ - g->nodes[n].class = class; -} - -void -ra_add_node_interference(struct ra_graph *g, - unsigned int n1, unsigned int n2) -{ - if (!g->nodes[n1].adjacency[n2]) { - ra_add_node_adjacency(g, n1, n2); - ra_add_node_adjacency(g, n2, n1); - } -} - -static GLboolean pq_test(struct ra_graph *g, unsigned int n) -{ - unsigned int j; - unsigned int q = 0; - int n_class = g->nodes[n].class; - - for (j = 0; j < g->nodes[n].adjacency_count; j++) { - unsigned int n2 = g->nodes[n].adjacency_list[j]; - unsigned int n2_class = g->nodes[n2].class; - - if (n != n2 && !g->nodes[n2].in_stack) { - q += g->regs->classes[n_class]->q[n2_class]; - } - } - - return q < g->regs->classes[n_class]->p; -} - -/** - * Simplifies the interference graph by pushing all - * trivially-colorable nodes into a stack of nodes to be colored, - * removing them from the graph, and rinsing and repeating. - * - * Returns GL_TRUE if all nodes were removed from the graph. GL_FALSE - * means that either spilling will be required, or optimistic coloring - * should be applied. - */ -GLboolean -ra_simplify(struct ra_graph *g) -{ - GLboolean progress = GL_TRUE; - int i; - - while (progress) { - progress = GL_FALSE; - - for (i = g->count - 1; i >= 0; i--) { - if (g->nodes[i].in_stack) - continue; - - if (pq_test(g, i)) { - g->stack[g->stack_count] = i; - g->stack_count++; - g->nodes[i].in_stack = GL_TRUE; - progress = GL_TRUE; - } - } - } - - for (i = 0; i < g->count; i++) { - if (!g->nodes[i].in_stack) - return GL_FALSE; - } - - return GL_TRUE; -} - -/** - * Pops nodes from the stack back into the graph, coloring them with - * registers as they go. - * - * If all nodes were trivially colorable, then this must succeed. If - * not (optimistic coloring), then it may return GL_FALSE; - */ -GLboolean -ra_select(struct ra_graph *g) -{ - int i; - - while (g->stack_count != 0) { - unsigned int r; - int n = g->stack[g->stack_count - 1]; - struct ra_class *c = g->regs->classes[g->nodes[n].class]; - - /* Find the lowest-numbered reg which is not used by a member - * of the graph adjacent to us. - */ - for (r = 0; r < g->regs->count; r++) { - if (!c->regs[r]) - continue; - - /* Check if any of our neighbors conflict with this register choice. */ - for (i = 0; i < g->nodes[n].adjacency_count; i++) { - unsigned int n2 = g->nodes[n].adjacency_list[i]; - - if (!g->nodes[n2].in_stack && - g->regs->regs[r].conflicts[g->nodes[n2].reg]) { - break; - } - } - if (i == g->nodes[n].adjacency_count) - break; - } - if (r == g->regs->count) - return GL_FALSE; - - g->nodes[n].reg = r; - g->nodes[n].in_stack = GL_FALSE; - g->stack_count--; - } - - return GL_TRUE; -} - -/** - * Optimistic register coloring: Just push the remaining nodes - * on the stack. They'll be colored first in ra_select(), and - * if they succeed then the locally-colorable nodes are still - * locally-colorable and the rest of the register allocation - * will succeed. - */ -void -ra_optimistic_color(struct ra_graph *g) -{ - unsigned int i; - - for (i = 0; i < g->count; i++) { - if (g->nodes[i].in_stack) - continue; - - g->stack[g->stack_count] = i; - g->stack_count++; - g->nodes[i].in_stack = GL_TRUE; - } -} - -GLboolean -ra_allocate_no_spills(struct ra_graph *g) -{ - if (!ra_simplify(g)) { - ra_optimistic_color(g); - } - return ra_select(g); -} - -unsigned int -ra_get_node_reg(struct ra_graph *g, unsigned int n) -{ - return g->nodes[n].reg; -} - -static float -ra_get_spill_benefit(struct ra_graph *g, unsigned int n) -{ - int j; - float benefit = 0; - int n_class = g->nodes[n].class; - - /* Define the benefit of eliminating an interference between n, n2 - * through spilling as q(C, B) / p(C). This is similar to the - * "count number of edges" approach of traditional graph coloring, - * but takes classes into account. - */ - for (j = 0; j < g->nodes[n].adjacency_count; j++) { - unsigned int n2 = g->nodes[n].adjacency_list[j]; - if (n != n2) { - unsigned int n2_class = g->nodes[n2].class; - benefit += ((float)g->regs->classes[n_class]->q[n2_class] / - g->regs->classes[n_class]->p); - } - } - - return benefit; -} - -/** - * Returns a node number to be spilled according to the cost/benefit using - * the pq test, or -1 if there are no spillable nodes. - */ -int -ra_get_best_spill_node(struct ra_graph *g) -{ - unsigned int best_node = -1; - unsigned int best_benefit = 0.0; - unsigned int n; - - for (n = 0; n < g->count; n++) { - float cost = g->nodes[n].spill_cost; - float benefit; - - if (cost <= 0.0) - continue; - - benefit = ra_get_spill_benefit(g, n); - - if (benefit / cost > best_benefit) { - best_benefit = benefit / cost; - best_node = n; - } - } - - return best_node; -} - -/** - * Only nodes with a spill cost set (cost != 0.0) will be considered - * for register spilling. - */ -void -ra_set_node_spill_cost(struct ra_graph *g, unsigned int n, float cost) -{ - g->nodes[n].spill_cost = cost; -} +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ + +/** @file register_allocate.c + * + * Graph-coloring register allocator. + * + * The basic idea of graph coloring is to make a node in a graph for + * every thing that needs a register (color) number assigned, and make + * edges in the graph between nodes that interfere (can't be allocated + * to the same register at the same time). + * + * During the "simplify" process, any any node with fewer edges than + * there are registers means that that edge can get assigned a + * register regardless of what its neighbors choose, so that node is + * pushed on a stack and removed (with its edges) from the graph. + * That likely causes other nodes to become trivially colorable as well. + * + * Then during the "select" process, nodes are popped off of that + * stack, their edges restored, and assigned a color different from + * their neighbors. Because they were pushed on the stack only when + * they were trivially colorable, any color chosen won't interfere + * with the registers to be popped later. + * + * The downside to most graph coloring is that real hardware often has + * limitations, like registers that need to be allocated to a node in + * pairs, or aligned on some boundary. This implementation follows + * the paper "Retargetable Graph-Coloring Register Allocation for + * Irregular Architectures" by Johan Runeson and Sven-Olof Nyström. + * + * In this system, there are register classes each containing various + * registers, and registers may interfere with other registers. For + * example, one might have a class of base registers, and a class of + * aligned register pairs that would each interfere with their pair of + * the base registers. Each node has a register class it needs to be + * assigned to. Define p(B) to be the size of register class B, and + * q(B,C) to be the number of registers in B that the worst choice + * register in C could conflict with. Then, this system replaces the + * basic graph coloring test of "fewer edges from this node than there + * are registers" with "For this node of class B, the sum of q(B,C) + * for each neighbor node of class C is less than pB". + * + * A nice feature of the pq test is that q(B,C) can be computed once + * up front and stored in a 2-dimensional array, so that the cost of + * coloring a node is constant with the number of registers. We do + * this during ra_set_finalize(). + */ + +#include + +#include "main/imports.h" +#include "main/macros.h" +#include "main/mtypes.h" +#include "register_allocate.h" + +#define NO_REG ~0 + +struct ra_reg { + GLboolean *conflicts; + unsigned int *conflict_list; + unsigned int conflict_list_size; + unsigned int num_conflicts; +}; + +struct ra_regs { + struct ra_reg *regs; + unsigned int count; + + struct ra_class **classes; + unsigned int class_count; +}; + +struct ra_class { + GLboolean *regs; + + /** + * p(B) in Runeson/Nyström paper. + * + * This is "how many regs are in the set." + */ + unsigned int p; + + /** + * q(B,C) (indexed by C, B is this register class) in + * Runeson/Nyström paper. This is "how many registers of B could + * the worst choice register from C conflict with". + */ + unsigned int *q; +}; + +struct ra_node { + /** @{ + * + * List of which nodes this node interferes with. This should be + * symmetric with the other node. + */ + GLboolean *adjacency; + unsigned int *adjacency_list; + unsigned int adjacency_count; + /** @} */ + + unsigned int class; + + /* Register, if assigned, or NO_REG. */ + unsigned int reg; + + /** + * Set when the node is in the trivially colorable stack. When + * set, the adjacency to this node is ignored, to implement the + * "remove the edge from the graph" in simplification without + * having to actually modify the adjacency_list. + */ + GLboolean in_stack; + + /* For an implementation that needs register spilling, this is the + * approximate cost of spilling this node. + */ + float spill_cost; +}; + +struct ra_graph { + struct ra_regs *regs; + /** + * the variables that need register allocation. + */ + struct ra_node *nodes; + unsigned int count; /**< count of nodes. */ + + unsigned int *stack; + unsigned int stack_count; +}; + +struct ra_regs * +ra_alloc_reg_set(unsigned int count) +{ + unsigned int i; + struct ra_regs *regs; + + regs = rzalloc(NULL, struct ra_regs); + regs->count = count; + regs->regs = rzalloc_array(regs, struct ra_reg, count); + + for (i = 0; i < count; i++) { + regs->regs[i].conflicts = rzalloc_array(regs->regs, GLboolean, count); + regs->regs[i].conflicts[i] = GL_TRUE; + + regs->regs[i].conflict_list = ralloc_array(regs->regs, unsigned int, 4); + regs->regs[i].conflict_list_size = 4; + regs->regs[i].conflict_list[0] = i; + regs->regs[i].num_conflicts = 1; + } + + return regs; +} + +static void +ra_add_conflict_list(struct ra_regs *regs, unsigned int r1, unsigned int r2) +{ + struct ra_reg *reg1 = ®s->regs[r1]; + + if (reg1->conflict_list_size == reg1->num_conflicts) { + reg1->conflict_list_size *= 2; + reg1->conflict_list = reralloc(regs->regs, reg1->conflict_list, + unsigned int, reg1->conflict_list_size); + } + reg1->conflict_list[reg1->num_conflicts++] = r2; + reg1->conflicts[r2] = GL_TRUE; +} + +void +ra_add_reg_conflict(struct ra_regs *regs, unsigned int r1, unsigned int r2) +{ + if (!regs->regs[r1].conflicts[r2]) { + ra_add_conflict_list(regs, r1, r2); + ra_add_conflict_list(regs, r2, r1); + } +} + +unsigned int +ra_alloc_reg_class(struct ra_regs *regs) +{ + struct ra_class *class; + + regs->classes = reralloc(regs->regs, regs->classes, struct ra_class *, + regs->class_count + 1); + + class = rzalloc(regs, struct ra_class); + regs->classes[regs->class_count] = class; + + class->regs = rzalloc_array(class, GLboolean, regs->count); + + return regs->class_count++; +} + +void +ra_class_add_reg(struct ra_regs *regs, unsigned int c, unsigned int r) +{ + struct ra_class *class = regs->classes[c]; + + class->regs[r] = GL_TRUE; + class->p++; +} + +/** + * Must be called after all conflicts and register classes have been + * set up and before the register set is used for allocation. + */ +void +ra_set_finalize(struct ra_regs *regs) +{ + unsigned int b, c; + + for (b = 0; b < regs->class_count; b++) { + regs->classes[b]->q = ralloc_array(regs, unsigned int, regs->class_count); + } + + /* Compute, for each class B and C, how many regs of B an + * allocation to C could conflict with. + */ + for (b = 0; b < regs->class_count; b++) { + for (c = 0; c < regs->class_count; c++) { + unsigned int rc; + int max_conflicts = 0; + + for (rc = 0; rc < regs->count; rc++) { + int conflicts = 0; + int i; + + if (!regs->classes[c]->regs[rc]) + continue; + + for (i = 0; i < regs->regs[rc].num_conflicts; i++) { + unsigned int rb = regs->regs[rc].conflict_list[i]; + if (regs->classes[b]->regs[rb]) + conflicts++; + } + max_conflicts = MAX2(max_conflicts, conflicts); + } + regs->classes[b]->q[c] = max_conflicts; + } + } +} + +static void +ra_add_node_adjacency(struct ra_graph *g, unsigned int n1, unsigned int n2) +{ + g->nodes[n1].adjacency[n2] = GL_TRUE; + g->nodes[n1].adjacency_list[g->nodes[n1].adjacency_count] = n2; + g->nodes[n1].adjacency_count++; +} + +struct ra_graph * +ra_alloc_interference_graph(struct ra_regs *regs, unsigned int count) +{ + struct ra_graph *g; + unsigned int i; + + g = rzalloc(regs, struct ra_graph); + g->regs = regs; + g->nodes = rzalloc_array(g, struct ra_node, count); + g->count = count; + + g->stack = rzalloc_array(g, unsigned int, count); + + for (i = 0; i < count; i++) { + g->nodes[i].adjacency = rzalloc_array(g, GLboolean, count); + g->nodes[i].adjacency_list = ralloc_array(g, unsigned int, count); + g->nodes[i].adjacency_count = 0; + ra_add_node_adjacency(g, i, i); + g->nodes[i].reg = NO_REG; + } + + return g; +} + +void +ra_set_node_class(struct ra_graph *g, + unsigned int n, unsigned int class) +{ + g->nodes[n].class = class; +} + +void +ra_add_node_interference(struct ra_graph *g, + unsigned int n1, unsigned int n2) +{ + if (!g->nodes[n1].adjacency[n2]) { + ra_add_node_adjacency(g, n1, n2); + ra_add_node_adjacency(g, n2, n1); + } +} + +static GLboolean pq_test(struct ra_graph *g, unsigned int n) +{ + unsigned int j; + unsigned int q = 0; + int n_class = g->nodes[n].class; + + for (j = 0; j < g->nodes[n].adjacency_count; j++) { + unsigned int n2 = g->nodes[n].adjacency_list[j]; + unsigned int n2_class = g->nodes[n2].class; + + if (n != n2 && !g->nodes[n2].in_stack) { + q += g->regs->classes[n_class]->q[n2_class]; + } + } + + return q < g->regs->classes[n_class]->p; +} + +/** + * Simplifies the interference graph by pushing all + * trivially-colorable nodes into a stack of nodes to be colored, + * removing them from the graph, and rinsing and repeating. + * + * Returns GL_TRUE if all nodes were removed from the graph. GL_FALSE + * means that either spilling will be required, or optimistic coloring + * should be applied. + */ +GLboolean +ra_simplify(struct ra_graph *g) +{ + GLboolean progress = GL_TRUE; + int i; + + while (progress) { + progress = GL_FALSE; + + for (i = g->count - 1; i >= 0; i--) { + if (g->nodes[i].in_stack || g->nodes[i].reg != NO_REG) + continue; + + if (pq_test(g, i)) { + g->stack[g->stack_count] = i; + g->stack_count++; + g->nodes[i].in_stack = GL_TRUE; + progress = GL_TRUE; + } + } + } + + for (i = 0; i < g->count; i++) { + if (!g->nodes[i].in_stack) + return GL_FALSE; + } + + return GL_TRUE; +} + +/** + * Pops nodes from the stack back into the graph, coloring them with + * registers as they go. + * + * If all nodes were trivially colorable, then this must succeed. If + * not (optimistic coloring), then it may return GL_FALSE; + */ +GLboolean +ra_select(struct ra_graph *g) +{ + int i; + + while (g->stack_count != 0) { + unsigned int r; + int n = g->stack[g->stack_count - 1]; + struct ra_class *c = g->regs->classes[g->nodes[n].class]; + + /* Find the lowest-numbered reg which is not used by a member + * of the graph adjacent to us. + */ + for (r = 0; r < g->regs->count; r++) { + if (!c->regs[r]) + continue; + + /* Check if any of our neighbors conflict with this register choice. */ + for (i = 0; i < g->nodes[n].adjacency_count; i++) { + unsigned int n2 = g->nodes[n].adjacency_list[i]; + + if (!g->nodes[n2].in_stack && + g->regs->regs[r].conflicts[g->nodes[n2].reg]) { + break; + } + } + if (i == g->nodes[n].adjacency_count) + break; + } + if (r == g->regs->count) + return GL_FALSE; + + g->nodes[n].reg = r; + g->nodes[n].in_stack = GL_FALSE; + g->stack_count--; + } + + return GL_TRUE; +} + +/** + * Optimistic register coloring: Just push the remaining nodes + * on the stack. They'll be colored first in ra_select(), and + * if they succeed then the locally-colorable nodes are still + * locally-colorable and the rest of the register allocation + * will succeed. + */ +void +ra_optimistic_color(struct ra_graph *g) +{ + unsigned int i; + + for (i = 0; i < g->count; i++) { + if (g->nodes[i].in_stack || g->nodes[i].reg != NO_REG) + continue; + + g->stack[g->stack_count] = i; + g->stack_count++; + g->nodes[i].in_stack = GL_TRUE; + } +} + +GLboolean +ra_allocate_no_spills(struct ra_graph *g) +{ + if (!ra_simplify(g)) { + ra_optimistic_color(g); + } + return ra_select(g); +} + +unsigned int +ra_get_node_reg(struct ra_graph *g, unsigned int n) +{ + return g->nodes[n].reg; +} + +/** + * Forces a node to a specific register. This can be used to avoid + * creating a register class containing one node when handling data + * that must live in a fixed location and is known to not conflict + * with other forced register assignment (as is common with shader + * input data). These nodes do not end up in the stack during + * ra_simplify(), and thus at ra_select() time it is as if they were + * the first popped off the stack and assigned their fixed locations. + * + * Must be called before ra_simplify(). + */ +void +ra_set_node_reg(struct ra_graph *g, unsigned int n, unsigned int reg) +{ + g->nodes[n].reg = reg; + g->nodes[n].in_stack = GL_FALSE; +} + +static float +ra_get_spill_benefit(struct ra_graph *g, unsigned int n) +{ + int j; + float benefit = 0; + int n_class = g->nodes[n].class; + + /* Define the benefit of eliminating an interference between n, n2 + * through spilling as q(C, B) / p(C). This is similar to the + * "count number of edges" approach of traditional graph coloring, + * but takes classes into account. + */ + for (j = 0; j < g->nodes[n].adjacency_count; j++) { + unsigned int n2 = g->nodes[n].adjacency_list[j]; + if (n != n2) { + unsigned int n2_class = g->nodes[n2].class; + benefit += ((float)g->regs->classes[n_class]->q[n2_class] / + g->regs->classes[n_class]->p); + } + } + + return benefit; +} + +/** + * Returns a node number to be spilled according to the cost/benefit using + * the pq test, or -1 if there are no spillable nodes. + */ +int +ra_get_best_spill_node(struct ra_graph *g) +{ + unsigned int best_node = -1; + unsigned int best_benefit = 0.0; + unsigned int n; + + for (n = 0; n < g->count; n++) { + float cost = g->nodes[n].spill_cost; + float benefit; + + if (cost <= 0.0) + continue; + + benefit = ra_get_spill_benefit(g, n); + + if (benefit / cost > best_benefit) { + best_benefit = benefit / cost; + best_node = n; + } + } + + return best_node; +} + +/** + * Only nodes with a spill cost set (cost != 0.0) will be considered + * for register spilling. + */ +void +ra_set_node_spill_cost(struct ra_graph *g, unsigned int n, float cost) +{ + g->nodes[n].spill_cost = cost; +} diff --git a/mesalib/src/mesa/program/register_allocate.h b/mesalib/src/mesa/program/register_allocate.h index bb9e2740a..5b95833f3 100644 --- a/mesalib/src/mesa/program/register_allocate.h +++ b/mesalib/src/mesa/program/register_allocate.h @@ -1,71 +1,72 @@ -/* - * Copyright © 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Eric Anholt - * - */ - -struct ra_class; -struct ra_regs; - -/* @{ - * Register set setup. - * - * This should be done once at backend initializaion, as - * ra_set_finalize is O(r^2*c^2). The registers may be virtual - * registers, such as aligned register pairs that conflict with the - * two real registers from which they are composed. - */ -struct ra_regs *ra_alloc_reg_set(unsigned int count); -unsigned int ra_alloc_reg_class(struct ra_regs *regs); -void ra_add_reg_conflict(struct ra_regs *regs, - unsigned int r1, unsigned int r2); -void ra_class_add_reg(struct ra_regs *regs, unsigned int c, unsigned int reg); -void ra_set_finalize(struct ra_regs *regs); -/** @} */ - -/** @{ Interference graph setup. - * - * Each interference graph node is a virtual variable in the IL. It - * is up to the user to ra_set_node_class() for the virtual variable, - * and compute live ranges and ra_node_interfere() between conflicting - * live ranges. - */ -struct ra_graph *ra_alloc_interference_graph(struct ra_regs *regs, - unsigned int count); -void ra_set_node_class(struct ra_graph *g, unsigned int n, unsigned int c); -void ra_add_node_interference(struct ra_graph *g, - unsigned int n1, unsigned int n2); -/** @} */ - -/** @{ Graph-coloring register allocation */ -GLboolean ra_simplify(struct ra_graph *g); -void ra_optimistic_color(struct ra_graph *g); -GLboolean ra_select(struct ra_graph *g); -GLboolean ra_allocate_no_spills(struct ra_graph *g); - -unsigned int ra_get_node_reg(struct ra_graph *g, unsigned int n); -void ra_set_node_spill_cost(struct ra_graph *g, unsigned int n, float cost); -int ra_get_best_spill_node(struct ra_graph *g); -/** @} */ - +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ + +struct ra_class; +struct ra_regs; + +/* @{ + * Register set setup. + * + * This should be done once at backend initializaion, as + * ra_set_finalize is O(r^2*c^2). The registers may be virtual + * registers, such as aligned register pairs that conflict with the + * two real registers from which they are composed. + */ +struct ra_regs *ra_alloc_reg_set(unsigned int count); +unsigned int ra_alloc_reg_class(struct ra_regs *regs); +void ra_add_reg_conflict(struct ra_regs *regs, + unsigned int r1, unsigned int r2); +void ra_class_add_reg(struct ra_regs *regs, unsigned int c, unsigned int reg); +void ra_set_finalize(struct ra_regs *regs); +/** @} */ + +/** @{ Interference graph setup. + * + * Each interference graph node is a virtual variable in the IL. It + * is up to the user to ra_set_node_class() for the virtual variable, + * and compute live ranges and ra_node_interfere() between conflicting + * live ranges. + */ +struct ra_graph *ra_alloc_interference_graph(struct ra_regs *regs, + unsigned int count); +void ra_set_node_class(struct ra_graph *g, unsigned int n, unsigned int c); +void ra_add_node_interference(struct ra_graph *g, + unsigned int n1, unsigned int n2); +/** @} */ + +/** @{ Graph-coloring register allocation */ +GLboolean ra_simplify(struct ra_graph *g); +void ra_optimistic_color(struct ra_graph *g); +GLboolean ra_select(struct ra_graph *g); +GLboolean ra_allocate_no_spills(struct ra_graph *g); + +unsigned int ra_get_node_reg(struct ra_graph *g, unsigned int n); +void ra_set_node_reg(struct ra_graph * g, unsigned int n, unsigned int reg); +void ra_set_node_spill_cost(struct ra_graph *g, unsigned int n, float cost); +int ra_get_best_spill_node(struct ra_graph *g); +/** @} */ + diff --git a/mesalib/src/mesa/state_tracker/st_atom_pixeltransfer.c b/mesalib/src/mesa/state_tracker/st_atom_pixeltransfer.c index 9557adc2d..57430b36f 100644 --- a/mesalib/src/mesa/state_tracker/st_atom_pixeltransfer.c +++ b/mesalib/src/mesa/state_tracker/st_atom_pixeltransfer.c @@ -195,18 +195,8 @@ get_pixel_transfer_program(struct gl_context *ctx, const struct state_key *key) { STATE_INTERNAL, STATE_PT_SCALE, 0, 0, 0 }; static const gl_state_index bias_state[STATE_LENGTH] = { STATE_INTERNAL, STATE_PT_BIAS, 0, 0, 0 }; - GLfloat scale[4], bias[4]; GLint scale_p, bias_p; - scale[0] = ctx->Pixel.RedScale; - scale[1] = ctx->Pixel.GreenScale; - scale[2] = ctx->Pixel.BlueScale; - scale[3] = ctx->Pixel.AlphaScale; - bias[0] = ctx->Pixel.RedBias; - bias[1] = ctx->Pixel.GreenBias; - bias[2] = ctx->Pixel.BlueBias; - bias[3] = ctx->Pixel.AlphaBias; - scale_p = _mesa_add_state_reference(params, scale_state); bias_p = _mesa_add_state_reference(params, bias_state); diff --git a/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c b/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c index 9cc40c3d9..e377861b8 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c +++ b/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c @@ -1,1543 +1,1541 @@ -/************************************************************************** - * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - - /* - * Authors: - * Brian Paul - */ - -#include "main/imports.h" -#include "main/image.h" -#include "main/bufferobj.h" -#include "main/macros.h" -#include "main/mfeatures.h" -#include "main/mtypes.h" -#include "main/pack.h" -#include "main/pbo.h" -#include "main/texformat.h" -#include "main/texstore.h" -#include "program/program.h" -#include "program/prog_print.h" -#include "program/prog_instruction.h" - -#include "st_atom.h" -#include "st_atom_constbuf.h" -#include "st_cb_drawpixels.h" -#include "st_cb_readpixels.h" -#include "st_cb_fbo.h" -#include "st_context.h" -#include "st_debug.h" -#include "st_format.h" -#include "st_program.h" -#include "st_texture.h" - -#include "pipe/p_context.h" -#include "pipe/p_defines.h" -#include "tgsi/tgsi_ureg.h" -#include "util/u_draw_quad.h" -#include "util/u_format.h" -#include "util/u_inlines.h" -#include "util/u_math.h" -#include "util/u_tile.h" -#include "cso_cache/cso_context.h" - - -#if FEATURE_drawpix - -/** - * Check if the given program is: - * 0: MOVE result.color, fragment.color; - * 1: END; - */ -static GLboolean -is_passthrough_program(const struct gl_fragment_program *prog) -{ - if (prog->Base.NumInstructions == 2) { - const struct prog_instruction *inst = prog->Base.Instructions; - if (inst[0].Opcode == OPCODE_MOV && - inst[1].Opcode == OPCODE_END && - inst[0].DstReg.File == PROGRAM_OUTPUT && - inst[0].DstReg.Index == FRAG_RESULT_COLOR && - inst[0].DstReg.WriteMask == WRITEMASK_XYZW && - inst[0].SrcReg[0].File == PROGRAM_INPUT && - inst[0].SrcReg[0].Index == FRAG_ATTRIB_COL0 && - inst[0].SrcReg[0].Swizzle == SWIZZLE_XYZW) { - return GL_TRUE; - } - } - return GL_FALSE; -} - - - -/** - * Make fragment shader for glDraw/CopyPixels. This shader is made - * by combining the pixel transfer shader with the user-defined shader. - * \param fpIn the current/incoming fragment program - * \param fpOut returns the combined fragment program - */ -void -st_make_drawpix_fragment_program(struct st_context *st, - struct gl_fragment_program *fpIn, - struct gl_fragment_program **fpOut) -{ - struct gl_program *newProg; - - if (is_passthrough_program(fpIn)) { - newProg = (struct gl_program *) _mesa_clone_fragment_program(st->ctx, - &st->pixel_xfer.program->Base); - } - else { -#if 0 - /* debug */ - printf("Base program:\n"); - _mesa_print_program(&fpIn->Base); - printf("DrawPix program:\n"); - _mesa_print_program(&st->pixel_xfer.program->Base.Base); -#endif - newProg = _mesa_combine_programs(st->ctx, - &st->pixel_xfer.program->Base.Base, - &fpIn->Base); - } - -#if 0 - /* debug */ - printf("Combined DrawPixels program:\n"); - _mesa_print_program(newProg); - printf("InputsRead: 0x%x\n", newProg->InputsRead); - printf("OutputsWritten: 0x%x\n", newProg->OutputsWritten); - _mesa_print_parameter_list(newProg->Parameters); -#endif - - *fpOut = (struct gl_fragment_program *) newProg; -} - - -/** - * Create fragment program that does a TEX() instruction to get a Z and/or - * stencil value value, then writes to FRAG_RESULT_DEPTH/FRAG_RESULT_STENCIL. - * Used for glDrawPixels(GL_DEPTH_COMPONENT / GL_STENCIL_INDEX). - * Pass fragment color through as-is. - * \return pointer to the gl_fragment program - */ -struct gl_fragment_program * -st_make_drawpix_z_stencil_program(struct st_context *st, - GLboolean write_depth, - GLboolean write_stencil) -{ - struct gl_context *ctx = st->ctx; - struct gl_program *p; - struct gl_fragment_program *fp; - GLuint ic = 0; - const GLuint shaderIndex = write_depth * 2 + write_stencil; - - assert(shaderIndex < Elements(st->drawpix.shaders)); - - if (st->drawpix.shaders[shaderIndex]) { - /* already have the proper shader */ - return st->drawpix.shaders[shaderIndex]; - } - - /* - * Create shader now - */ - p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); - if (!p) - return NULL; - - p->NumInstructions = write_depth ? 2 : 1; - p->NumInstructions += write_stencil ? 1 : 0; - - p->Instructions = _mesa_alloc_instructions(p->NumInstructions); - if (!p->Instructions) { - ctx->Driver.DeleteProgram(ctx, p); - return NULL; - } - _mesa_init_instructions(p->Instructions, p->NumInstructions); - - if (write_depth) { - /* TEX result.depth, fragment.texcoord[0], texture[0], 2D; */ - p->Instructions[ic].Opcode = OPCODE_TEX; - p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; - p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPTH; - p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z; - p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; - p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; - p->Instructions[ic].TexSrcUnit = 0; - p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; - ic++; - } - - if (write_stencil) { - /* TEX result.stencil, fragment.texcoord[0], texture[0], 2D; */ - p->Instructions[ic].Opcode = OPCODE_TEX; - p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; - p->Instructions[ic].DstReg.Index = FRAG_RESULT_STENCIL; - p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Y; - p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; - p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; - p->Instructions[ic].TexSrcUnit = 1; - p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; - ic++; - } - - /* END; */ - p->Instructions[ic++].Opcode = OPCODE_END; - - assert(ic == p->NumInstructions); - - p->InputsRead = FRAG_BIT_TEX0 | FRAG_BIT_COL0; - p->OutputsWritten = 0; - if (write_depth) - p->OutputsWritten |= BITFIELD64_BIT(FRAG_RESULT_DEPTH); - if (write_stencil) - p->OutputsWritten |= BITFIELD64_BIT(FRAG_RESULT_STENCIL); - - p->SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */ - if (write_stencil) - p->SamplersUsed |= 1 << 1; - - fp = (struct gl_fragment_program *) p; - - /* save the new shader */ - st->drawpix.shaders[shaderIndex] = fp; - - return fp; -} - - -/** - * Create a simple vertex shader that just passes through the - * vertex position and texcoord (and optionally, color). - */ -static void * -make_passthrough_vertex_shader(struct st_context *st, - GLboolean passColor) -{ - if (!st->drawpix.vert_shaders[passColor]) { - struct ureg_program *ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); - - if (ureg == NULL) - return NULL; - - /* MOV result.pos, vertex.pos; */ - ureg_MOV(ureg, - ureg_DECL_output( ureg, TGSI_SEMANTIC_POSITION, 0 ), - ureg_DECL_vs_input( ureg, 0 )); - - /* MOV result.texcoord0, vertex.attr[1]; */ - ureg_MOV(ureg, - ureg_DECL_output( ureg, TGSI_SEMANTIC_GENERIC, 0 ), - ureg_DECL_vs_input( ureg, 1 )); - - if (passColor) { - /* MOV result.color0, vertex.attr[2]; */ - ureg_MOV(ureg, - ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, 0 ), - ureg_DECL_vs_input( ureg, 2 )); - } - - ureg_END( ureg ); - - st->drawpix.vert_shaders[passColor] = - ureg_create_shader_and_destroy( ureg, st->pipe ); - } - - return st->drawpix.vert_shaders[passColor]; -} - - -/** - * Return a texture base format for drawing/copying an image - * of the given format. - */ -static GLenum -base_format(GLenum format) -{ - switch (format) { - case GL_DEPTH_COMPONENT: - return GL_DEPTH_COMPONENT; - case GL_DEPTH_STENCIL: - return GL_DEPTH_STENCIL; - case GL_STENCIL_INDEX: - return GL_STENCIL_INDEX; - default: - return GL_RGBA; - } -} - - -/** - * Return a texture internalFormat for drawing/copying an image - * of the given format and type. - */ -static GLenum -internal_format(struct gl_context *ctx, GLenum format, GLenum type) -{ - switch (format) { - case GL_DEPTH_COMPONENT: - return GL_DEPTH_COMPONENT; - case GL_DEPTH_STENCIL: - return GL_DEPTH_STENCIL; - case GL_STENCIL_INDEX: - return GL_STENCIL_INDEX; - default: - if (_mesa_is_integer_format(format)) { - switch (type) { - case GL_BYTE: - return GL_RGBA8I; - case GL_UNSIGNED_BYTE: - return GL_RGBA8UI; - case GL_SHORT: - return GL_RGBA16I; - case GL_UNSIGNED_SHORT: - return GL_RGBA16UI; - case GL_INT: - return GL_RGBA32I; - case GL_UNSIGNED_INT: - return GL_RGBA32UI; - default: - assert(0 && "Unexpected type in internal_format()"); - return GL_RGBA_INTEGER; - } - } - else { - switch (type) { - case GL_UNSIGNED_BYTE: - case GL_UNSIGNED_INT_8_8_8_8: - case GL_UNSIGNED_INT_8_8_8_8_REV: - default: - return GL_RGBA8; - - case GL_UNSIGNED_BYTE_3_3_2: - case GL_UNSIGNED_BYTE_2_3_3_REV: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - return GL_RGBA4; - - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_5_6_5_REV: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - return GL_RGB5_A1; - - case GL_UNSIGNED_INT_10_10_10_2: - case GL_UNSIGNED_INT_2_10_10_10_REV: - return GL_RGB10_A2; - - case GL_UNSIGNED_SHORT: - case GL_UNSIGNED_INT: - return GL_RGBA16; - - case GL_BYTE: - return - ctx->Extensions.EXT_texture_snorm ? GL_RGBA8_SNORM : GL_RGBA8; - - case GL_SHORT: - case GL_INT: - return - ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16; - - case GL_HALF_FLOAT_ARB: - return - ctx->Extensions.ARB_texture_float ? GL_RGBA16F : - ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16; - - case GL_FLOAT: - case GL_DOUBLE: - return - ctx->Extensions.ARB_texture_float ? GL_RGBA32F : - ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16; - - case GL_UNSIGNED_INT_5_9_9_9_REV: - assert(ctx->Extensions.EXT_texture_shared_exponent); - return GL_RGB9_E5; - - case GL_UNSIGNED_INT_10F_11F_11F_REV: - assert(ctx->Extensions.EXT_packed_float); - return GL_R11F_G11F_B10F; - } - } - } -} - - -/** - * Create a temporary texture to hold an image of the given size. - * If width, height are not POT and the driver only handles POT textures, - * allocate the next larger size of texture that is POT. - */ -static struct pipe_resource * -alloc_texture(struct st_context *st, GLsizei width, GLsizei height, - enum pipe_format texFormat) -{ - struct pipe_resource *pt; - - pt = st_texture_create(st, st->internal_target, texFormat, 0, - width, height, 1, 1, PIPE_BIND_SAMPLER_VIEW); - - return pt; -} - - -/** - * Make texture containing an image for glDrawPixels image. - * If 'pixels' is NULL, leave the texture image data undefined. - */ -static struct pipe_resource * -make_texture(struct st_context *st, - GLsizei width, GLsizei height, GLenum format, GLenum type, - const struct gl_pixelstore_attrib *unpack, - const GLvoid *pixels) -{ - struct gl_context *ctx = st->ctx; - struct pipe_context *pipe = st->pipe; - gl_format mformat; - struct pipe_resource *pt; - enum pipe_format pipeFormat; - GLuint cpp; - GLenum baseFormat, intFormat; - - baseFormat = base_format(format); - intFormat = internal_format(ctx, format, type); - - mformat = st_ChooseTextureFormat_renderable(ctx, intFormat, - format, type, GL_FALSE); - assert(mformat); - - pipeFormat = st_mesa_format_to_pipe_format(mformat); - assert(pipeFormat); - cpp = util_format_get_blocksize(pipeFormat); - - pixels = _mesa_map_pbo_source(ctx, unpack, pixels); - if (!pixels) - return NULL; - - /* alloc temporary texture */ - pt = alloc_texture(st, width, height, pipeFormat); - if (!pt) { - _mesa_unmap_pbo_source(ctx, unpack); - return NULL; - } - - { - struct pipe_transfer *transfer; - static const GLuint dstImageOffsets = 0; - GLboolean success; - GLubyte *dest; - const GLbitfield imageTransferStateSave = ctx->_ImageTransferState; - - /* we'll do pixel transfer in a fragment shader */ - ctx->_ImageTransferState = 0x0; - - transfer = pipe_get_transfer(st->pipe, pt, 0, 0, - PIPE_TRANSFER_WRITE, 0, 0, - width, height); - - /* map texture transfer */ - dest = pipe_transfer_map(pipe, transfer); - - - /* Put image into texture transfer. - * Note that the image is actually going to be upside down in - * the texture. We deal with that with texcoords. - */ - success = _mesa_texstore(ctx, 2, /* dims */ - baseFormat, /* baseInternalFormat */ - mformat, /* gl_format */ - dest, /* dest */ - 0, 0, 0, /* dstX/Y/Zoffset */ - transfer->stride, /* dstRowStride, bytes */ - &dstImageOffsets, /* dstImageOffsets */ - width, height, 1, /* size */ - format, type, /* src format/type */ - pixels, /* data source */ - unpack); - - /* unmap */ - pipe_transfer_unmap(pipe, transfer); - pipe->transfer_destroy(pipe, transfer); - - assert(success); - - /* restore */ - ctx->_ImageTransferState = imageTransferStateSave; - } - - _mesa_unmap_pbo_source(ctx, unpack); - - return pt; -} - - -/** - * Draw quad with texcoords and optional color. - * Coords are gallium window coords with y=0=top. - * \param color may be null - * \param invertTex if true, flip texcoords vertically - */ -static void -draw_quad(struct gl_context *ctx, GLfloat x0, GLfloat y0, GLfloat z, - GLfloat x1, GLfloat y1, const GLfloat *color, - GLboolean invertTex, GLfloat maxXcoord, GLfloat maxYcoord) -{ - struct st_context *st = st_context(ctx); - struct pipe_context *pipe = st->pipe; - GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */ - - /* setup vertex data */ - { - const struct gl_framebuffer *fb = st->ctx->DrawBuffer; - const GLfloat fb_width = (GLfloat) fb->Width; - const GLfloat fb_height = (GLfloat) fb->Height; - const GLfloat clip_x0 = x0 / fb_width * 2.0f - 1.0f; - const GLfloat clip_y0 = y0 / fb_height * 2.0f - 1.0f; - const GLfloat clip_x1 = x1 / fb_width * 2.0f - 1.0f; - const GLfloat clip_y1 = y1 / fb_height * 2.0f - 1.0f; - const GLfloat sLeft = 0.0f, sRight = maxXcoord; - const GLfloat tTop = invertTex ? maxYcoord : 0.0f; - const GLfloat tBot = invertTex ? 0.0f : maxYcoord; - GLuint i; - - /* upper-left */ - verts[0][0][0] = clip_x0; /* v[0].attr[0].x */ - verts[0][0][1] = clip_y0; /* v[0].attr[0].y */ - - /* upper-right */ - verts[1][0][0] = clip_x1; - verts[1][0][1] = clip_y0; - - /* lower-right */ - verts[2][0][0] = clip_x1; - verts[2][0][1] = clip_y1; - - /* lower-left */ - verts[3][0][0] = clip_x0; - verts[3][0][1] = clip_y1; - - verts[0][1][0] = sLeft; /* v[0].attr[1].S */ - verts[0][1][1] = tTop; /* v[0].attr[1].T */ - verts[1][1][0] = sRight; - verts[1][1][1] = tTop; - verts[2][1][0] = sRight; - verts[2][1][1] = tBot; - verts[3][1][0] = sLeft; - verts[3][1][1] = tBot; - - /* same for all verts: */ - if (color) { - for (i = 0; i < 4; i++) { - verts[i][0][2] = z; /* v[i].attr[0].z */ - verts[i][0][3] = 1.0f; /* v[i].attr[0].w */ - verts[i][2][0] = color[0]; /* v[i].attr[2].r */ - verts[i][2][1] = color[1]; /* v[i].attr[2].g */ - verts[i][2][2] = color[2]; /* v[i].attr[2].b */ - verts[i][2][3] = color[3]; /* v[i].attr[2].a */ - verts[i][1][2] = 0.0f; /* v[i].attr[1].R */ - verts[i][1][3] = 1.0f; /* v[i].attr[1].Q */ - } - } - else { - for (i = 0; i < 4; i++) { - verts[i][0][2] = z; /*Z*/ - verts[i][0][3] = 1.0f; /*W*/ - verts[i][1][2] = 0.0f; /*R*/ - verts[i][1][3] = 1.0f; /*Q*/ - } - } - } - - { - struct pipe_resource *buf; - - /* allocate/load buffer object with vertex data */ - buf = pipe_buffer_create(pipe->screen, - PIPE_BIND_VERTEX_BUFFER, - PIPE_USAGE_STATIC, - sizeof(verts)); - pipe_buffer_write(st->pipe, buf, 0, sizeof(verts), verts); - - util_draw_vertex_buffer(pipe, st->cso_context, buf, 0, - PIPE_PRIM_QUADS, - 4, /* verts */ - 3); /* attribs/vert */ - pipe_resource_reference(&buf, NULL); - } -} - - - -static void -draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, - GLsizei width, GLsizei height, - GLfloat zoomX, GLfloat zoomY, - struct pipe_sampler_view **sv, - int num_sampler_view, - void *driver_vp, - void *driver_fp, - const GLfloat *color, - GLboolean invertTex, - GLboolean write_depth, GLboolean write_stencil) -{ - struct st_context *st = st_context(ctx); - struct pipe_context *pipe = st->pipe; - struct cso_context *cso = st->cso_context; - GLfloat x0, y0, x1, y1; - GLsizei maxSize; - boolean normalized = sv[0]->texture->target != PIPE_TEXTURE_RECT; - - /* limit checks */ - /* XXX if DrawPixels image is larger than max texture size, break - * it up into chunks. - */ - maxSize = 1 << (pipe->screen->get_param(pipe->screen, - PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); - assert(width <= maxSize); - assert(height <= maxSize); - - cso_save_rasterizer(cso); - cso_save_viewport(cso); - cso_save_samplers(cso); - cso_save_fragment_sampler_views(cso); - cso_save_fragment_shader(cso); - cso_save_vertex_shader(cso); - cso_save_vertex_elements(cso); - cso_save_vertex_buffers(cso); - if (write_stencil) { - cso_save_depth_stencil_alpha(cso); - cso_save_blend(cso); - } - - /* rasterizer state: just scissor */ - { - struct pipe_rasterizer_state rasterizer; - memset(&rasterizer, 0, sizeof(rasterizer)); - rasterizer.clamp_fragment_color = ctx->Color._ClampFragmentColor; - rasterizer.gl_rasterization_rules = 1; - rasterizer.scissor = ctx->Scissor.Enabled; - cso_set_rasterizer(cso, &rasterizer); - } - - if (write_stencil) { - /* Stencil writing bypasses the normal fragment pipeline to - * disable color writing and set stencil test to always pass. - */ - struct pipe_depth_stencil_alpha_state dsa; - struct pipe_blend_state blend; - - /* depth/stencil */ - memset(&dsa, 0, sizeof(dsa)); - dsa.stencil[0].enabled = 1; - dsa.stencil[0].func = PIPE_FUNC_ALWAYS; - dsa.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff; - dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; - if (write_depth) { - /* writing depth+stencil: depth test always passes */ - dsa.depth.enabled = 1; - dsa.depth.writemask = ctx->Depth.Mask; - dsa.depth.func = PIPE_FUNC_ALWAYS; - } - cso_set_depth_stencil_alpha(cso, &dsa); - - /* blend (colormask) */ - memset(&blend, 0, sizeof(blend)); - cso_set_blend(cso, &blend); - } - - /* fragment shader state: TEX lookup program */ - cso_set_fragment_shader_handle(cso, driver_fp); - - /* vertex shader state: position + texcoord pass-through */ - cso_set_vertex_shader_handle(cso, driver_vp); - - - /* texture sampling state: */ - { - struct pipe_sampler_state sampler; - memset(&sampler, 0, sizeof(sampler)); - sampler.wrap_s = PIPE_TEX_WRAP_CLAMP; - sampler.wrap_t = PIPE_TEX_WRAP_CLAMP; - sampler.wrap_r = PIPE_TEX_WRAP_CLAMP; - sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; - sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; - sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; - sampler.normalized_coords = normalized; - - cso_single_sampler(cso, 0, &sampler); - if (num_sampler_view > 1) { - cso_single_sampler(cso, 1, &sampler); - } - cso_single_sampler_done(cso); - } - - /* viewport state: viewport matching window dims */ - { - const float w = (float) ctx->DrawBuffer->Width; - const float h = (float) ctx->DrawBuffer->Height; - struct pipe_viewport_state vp; - vp.scale[0] = 0.5f * w; - vp.scale[1] = -0.5f * h; - vp.scale[2] = 0.5f; - vp.scale[3] = 1.0f; - vp.translate[0] = 0.5f * w; - vp.translate[1] = 0.5f * h; - vp.translate[2] = 0.5f; - vp.translate[3] = 0.0f; - cso_set_viewport(cso, &vp); - } - - cso_set_vertex_elements(cso, 3, st->velems_util_draw); - - /* texture state: */ - cso_set_fragment_sampler_views(cso, num_sampler_view, sv); - - /* Compute Gallium window coords (y=0=top) with pixel zoom. - * Recall that these coords are transformed by the current - * vertex shader and viewport transformation. - */ - if (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM) { - y = ctx->DrawBuffer->Height - (int) (y + height * ctx->Pixel.ZoomY); - invertTex = !invertTex; - } - - x0 = (GLfloat) x; - x1 = x + width * ctx->Pixel.ZoomX; - y0 = (GLfloat) y; - y1 = y + height * ctx->Pixel.ZoomY; - - /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */ - z = z * 2.0 - 1.0; - - draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex, - normalized ? ((GLfloat) width / sv[0]->texture->width0) : (GLfloat)width, - normalized ? ((GLfloat) height / sv[0]->texture->height0) : (GLfloat)height); - - /* restore state */ - cso_restore_rasterizer(cso); - cso_restore_viewport(cso); - cso_restore_samplers(cso); - cso_restore_fragment_sampler_views(cso); - cso_restore_fragment_shader(cso); - cso_restore_vertex_shader(cso); - cso_restore_vertex_elements(cso); - cso_restore_vertex_buffers(cso); - if (write_stencil) { - cso_restore_depth_stencil_alpha(cso); - cso_restore_blend(cso); - } -} - - -/** - * Software fallback to do glDrawPixels(GL_STENCIL_INDEX) when we - * can't use a fragment shader to write stencil values. - */ -static void -draw_stencil_pixels(struct gl_context *ctx, GLint x, GLint y, - GLsizei width, GLsizei height, GLenum format, GLenum type, - const struct gl_pixelstore_attrib *unpack, - const GLvoid *pixels) -{ - struct st_context *st = st_context(ctx); - struct pipe_context *pipe = st->pipe; - struct st_renderbuffer *strb; - enum pipe_transfer_usage usage; - struct pipe_transfer *pt; - const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; - GLint skipPixels; - ubyte *stmap; - struct gl_pixelstore_attrib clippedUnpack = *unpack; - - if (!zoom) { - if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height, - &clippedUnpack)) { - /* totally clipped */ - return; - } - } - - strb = st_renderbuffer(ctx->DrawBuffer-> - Attachment[BUFFER_STENCIL].Renderbuffer); - - if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { - y = ctx->DrawBuffer->Height - y - height; - } - - if(format != GL_DEPTH_STENCIL && - util_format_get_component_bits(strb->format, - UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) - usage = PIPE_TRANSFER_READ_WRITE; - else - usage = PIPE_TRANSFER_WRITE; - - pt = pipe_get_transfer(st_context(ctx)->pipe, strb->texture, 0, 0, - usage, x, y, - width, height); - - stmap = pipe_transfer_map(pipe, pt); - - pixels = _mesa_map_pbo_source(ctx, &clippedUnpack, pixels); - assert(pixels); - - /* if width > MAX_WIDTH, have to process image in chunks */ - skipPixels = 0; - while (skipPixels < width) { - const GLint spanX = skipPixels; - const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); - GLint row; - for (row = 0; row < height; row++) { - GLubyte sValues[MAX_WIDTH]; - GLuint zValues[MAX_WIDTH]; - GLenum destType = GL_UNSIGNED_BYTE; - const GLvoid *source = _mesa_image_address2d(&clippedUnpack, pixels, - width, height, - format, type, - row, skipPixels); - _mesa_unpack_stencil_span(ctx, spanWidth, destType, sValues, - type, source, &clippedUnpack, - ctx->_ImageTransferState); - - if (format == GL_DEPTH_STENCIL) { - _mesa_unpack_depth_span(ctx, spanWidth, GL_UNSIGNED_INT, zValues, - (1 << 24) - 1, type, source, - &clippedUnpack); - } - - if (zoom) { - _mesa_problem(ctx, "Gallium glDrawPixels(GL_STENCIL) with " - "zoom not complete"); - } - - { - GLint spanY; - - if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { - spanY = height - row - 1; - } - else { - spanY = row; - } - - /* now pack the stencil (and Z) values in the dest format */ - switch (pt->resource->format) { - case PIPE_FORMAT_S8_USCALED: - { - ubyte *dest = stmap + spanY * pt->stride + spanX; - assert(usage == PIPE_TRANSFER_WRITE); - memcpy(dest, sValues, spanWidth); - } - break; - case PIPE_FORMAT_Z24_UNORM_S8_USCALED: - if (format == GL_DEPTH_STENCIL) { - uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); - GLint k; - assert(usage == PIPE_TRANSFER_WRITE); - for (k = 0; k < spanWidth; k++) { - dest[k] = zValues[k] | (sValues[k] << 24); - } - } - else { - uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); - GLint k; - assert(usage == PIPE_TRANSFER_READ_WRITE); - for (k = 0; k < spanWidth; k++) { - dest[k] = (dest[k] & 0xffffff) | (sValues[k] << 24); - } - } - break; - case PIPE_FORMAT_S8_USCALED_Z24_UNORM: - if (format == GL_DEPTH_STENCIL) { - uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); - GLint k; - assert(usage == PIPE_TRANSFER_WRITE); - for (k = 0; k < spanWidth; k++) { - dest[k] = (zValues[k] << 8) | (sValues[k] & 0xff); - } - } - else { - uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); - GLint k; - assert(usage == PIPE_TRANSFER_READ_WRITE); - for (k = 0; k < spanWidth; k++) { - dest[k] = (dest[k] & 0xffffff00) | (sValues[k] & 0xff); - } - } - break; - default: - assert(0); - } - } - } - skipPixels += spanWidth; - } - - _mesa_unmap_pbo_source(ctx, &clippedUnpack); - - /* unmap the stencil buffer */ - pipe_transfer_unmap(pipe, pt); - pipe->transfer_destroy(pipe, pt); -} - - -/** - * Get fragment program variant for a glDrawPixels or glCopyPixels - * command for RGBA data. - */ -static struct st_fp_variant * -get_color_fp_variant(struct st_context *st) -{ - struct gl_context *ctx = st->ctx; - struct st_fp_variant_key key; - struct st_fp_variant *fpv; - - memset(&key, 0, sizeof(key)); - - key.st = st; - key.drawpixels = 1; - key.scaleAndBias = (ctx->Pixel.RedBias != 0.0 || - ctx->Pixel.RedScale != 1.0 || - ctx->Pixel.GreenBias != 0.0 || - ctx->Pixel.GreenScale != 1.0 || - ctx->Pixel.BlueBias != 0.0 || - ctx->Pixel.BlueScale != 1.0 || - ctx->Pixel.AlphaBias != 0.0 || - ctx->Pixel.AlphaScale != 1.0); - key.pixelMaps = ctx->Pixel.MapColorFlag; - - fpv = st_get_fp_variant(st, st->fp, &key); - - return fpv; -} - - -/** - * Get fragment program variant for a glDrawPixels or glCopyPixels - * command for depth/stencil data. - */ -static struct st_fp_variant * -get_depth_stencil_fp_variant(struct st_context *st, GLboolean write_depth, - GLboolean write_stencil) -{ - struct st_fp_variant_key key; - struct st_fp_variant *fpv; - - memset(&key, 0, sizeof(key)); - - key.st = st; - key.drawpixels = 1; - key.drawpixels_z = write_depth; - key.drawpixels_stencil = write_stencil; - - fpv = st_get_fp_variant(st, st->fp, &key); - - return fpv; -} - - -/** - * Called via ctx->Driver.DrawPixels() - */ -static void -st_DrawPixels(struct gl_context *ctx, GLint x, GLint y, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) -{ - void *driver_vp, *driver_fp; - struct st_context *st = st_context(ctx); - const GLfloat *color; - struct pipe_context *pipe = st->pipe; - GLboolean write_stencil = GL_FALSE, write_depth = GL_FALSE; - struct pipe_sampler_view *sv[2]; - int num_sampler_view = 1; - enum pipe_format stencil_format = PIPE_FORMAT_NONE; - struct st_fp_variant *fpv; - - if (format == GL_DEPTH_STENCIL) - write_stencil = write_depth = GL_TRUE; - else if (format == GL_STENCIL_INDEX) - write_stencil = GL_TRUE; - else if (format == GL_DEPTH_COMPONENT) - write_depth = GL_TRUE; - - if (write_stencil) { - enum pipe_format tex_format; - /* can we write to stencil if not fallback */ - if (!pipe->screen->get_param(pipe->screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) - goto stencil_fallback; - - tex_format = st_choose_format(st->pipe->screen, base_format(format), - PIPE_TEXTURE_2D, - 0, PIPE_BIND_SAMPLER_VIEW); - if (tex_format == PIPE_FORMAT_Z24_UNORM_S8_USCALED) - stencil_format = PIPE_FORMAT_X24S8_USCALED; - else if (tex_format == PIPE_FORMAT_S8_USCALED_Z24_UNORM) - stencil_format = PIPE_FORMAT_S8X24_USCALED; - else - stencil_format = PIPE_FORMAT_S8_USCALED; - if (stencil_format == PIPE_FORMAT_NONE) - goto stencil_fallback; - } - - /* Mesa state should be up to date by now */ - assert(ctx->NewState == 0x0); - - st_validate_state(st); - - /* - * Get vertex/fragment shaders - */ - if (write_depth || write_stencil) { - fpv = get_depth_stencil_fp_variant(st, write_depth, write_stencil); - - driver_fp = fpv->driver_shader; - - driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); - - color = ctx->Current.RasterColor; - } - else { - fpv = get_color_fp_variant(st); - - driver_fp = fpv->driver_shader; - - driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); - - color = NULL; - if (st->pixel_xfer.pixelmap_enabled) { - sv[1] = st->pixel_xfer.pixelmap_sampler_view; - num_sampler_view++; - } - } - - /* update fragment program constants */ - st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT); - - /* draw with textured quad */ - { - struct pipe_resource *pt - = make_texture(st, width, height, format, type, unpack, pixels); - if (pt) { - sv[0] = st_create_texture_sampler_view(st->pipe, pt); - - if (sv[0]) { - if (write_stencil) { - sv[1] = st_create_texture_sampler_view_format(st->pipe, pt, - stencil_format); - num_sampler_view++; - } - - draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2], - width, height, - ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, - sv, - num_sampler_view, - driver_vp, - driver_fp, - color, GL_FALSE, write_depth, write_stencil); - pipe_sampler_view_reference(&sv[0], NULL); - if (num_sampler_view > 1) - pipe_sampler_view_reference(&sv[1], NULL); - } - pipe_resource_reference(&pt, NULL); - } - } - return; - -stencil_fallback: - draw_stencil_pixels(ctx, x, y, width, height, format, type, - unpack, pixels); -} - - - -/** - * Software fallback for glCopyPixels(GL_STENCIL). - */ -static void -copy_stencil_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, - GLsizei width, GLsizei height, - GLint dstx, GLint dsty) -{ - struct st_renderbuffer *rbDraw; - struct pipe_context *pipe = st_context(ctx)->pipe; - enum pipe_transfer_usage usage; - struct pipe_transfer *ptDraw; - ubyte *drawMap; - ubyte *buffer; - int i; - - buffer = malloc(width * height * sizeof(ubyte)); - if (!buffer) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)"); - return; - } - - /* Get the dest renderbuffer. If there's a wrapper, use the - * underlying renderbuffer. - */ - rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer); - if (rbDraw->Base.Wrapped) - rbDraw = st_renderbuffer(rbDraw->Base.Wrapped); - - /* this will do stencil pixel transfer ops */ - st_read_stencil_pixels(ctx, srcx, srcy, width, height, - GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, - &ctx->DefaultPacking, buffer); - - if (0) { - /* debug code: dump stencil values */ - GLint row, col; - for (row = 0; row < height; row++) { - printf("%3d: ", row); - for (col = 0; col < width; col++) { - printf("%02x ", buffer[col + row * width]); - } - printf("\n"); - } - } - - if (util_format_get_component_bits(rbDraw->format, - UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) - usage = PIPE_TRANSFER_READ_WRITE; - else - usage = PIPE_TRANSFER_WRITE; - - if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { - dsty = rbDraw->Base.Height - dsty - height; - } - - ptDraw = pipe_get_transfer(st_context(ctx)->pipe, - rbDraw->texture, 0, 0, - usage, dstx, dsty, - width, height); - - assert(util_format_get_blockwidth(ptDraw->resource->format) == 1); - assert(util_format_get_blockheight(ptDraw->resource->format) == 1); - - /* map the stencil buffer */ - drawMap = pipe_transfer_map(pipe, ptDraw); - - /* draw */ - /* XXX PixelZoom not handled yet */ - for (i = 0; i < height; i++) { - ubyte *dst; - const ubyte *src; - int y; - - y = i; - - if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { - y = height - y - 1; - } - - dst = drawMap + y * ptDraw->stride; - src = buffer + i * width; - - switch (ptDraw->resource->format) { - case PIPE_FORMAT_Z24_UNORM_S8_USCALED: - { - uint *dst4 = (uint *) dst; - int j; - assert(usage == PIPE_TRANSFER_READ_WRITE); - for (j = 0; j < width; j++) { - *dst4 = (*dst4 & 0xffffff) | (src[j] << 24); - dst4++; - } - } - break; - case PIPE_FORMAT_S8_USCALED_Z24_UNORM: - { - uint *dst4 = (uint *) dst; - int j; - assert(usage == PIPE_TRANSFER_READ_WRITE); - for (j = 0; j < width; j++) { - *dst4 = (*dst4 & 0xffffff00) | (src[j] & 0xff); - dst4++; - } - } - break; - case PIPE_FORMAT_S8_USCALED: - assert(usage == PIPE_TRANSFER_WRITE); - memcpy(dst, src, width); - break; - default: - assert(0); - } - } - - free(buffer); - - /* unmap the stencil buffer */ - pipe_transfer_unmap(pipe, ptDraw); - pipe->transfer_destroy(pipe, ptDraw); -} - - -/** Do the src/dest regions overlap? */ -static GLboolean -regions_overlap(GLint srcX, GLint srcY, GLint dstX, GLint dstY, - GLsizei width, GLsizei height) -{ - if (srcX + width <= dstX || - dstX + width <= srcX || - srcY + height <= dstY || - dstY + height <= srcY) - return GL_FALSE; - else - return GL_TRUE; -} - - -/** - * Try to do a glCopyPixels for simple cases with a blit by calling - * pipe->resource_copy_region(). - * - * We can do this when we're copying color pixels (depth/stencil - * eventually) with no pixel zoom, no pixel transfer ops, no - * per-fragment ops, the src/dest regions don't overlap and the - * src/dest pixel formats are the same. - */ -static GLboolean -blit_copy_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, - GLsizei width, GLsizei height, - GLint dstx, GLint dsty, GLenum type) -{ - struct st_context *st = st_context(ctx); - struct pipe_context *pipe = st->pipe; - struct gl_pixelstore_attrib pack, unpack; - GLint readX, readY, readW, readH; - - if (type == GL_COLOR && - ctx->Pixel.ZoomX == 1.0 && - ctx->Pixel.ZoomY == 1.0 && - ctx->_ImageTransferState == 0x0 && - !ctx->Color.BlendEnabled && - !ctx->Color.AlphaEnabled && - !ctx->Depth.Test && - !ctx->Fog.Enabled && - !ctx->Stencil.Enabled && - !ctx->FragmentProgram.Enabled && - !ctx->VertexProgram.Enabled && - !ctx->Shader.CurrentFragmentProgram && - st_fb_orientation(ctx->ReadBuffer) == st_fb_orientation(ctx->DrawBuffer) && - ctx->DrawBuffer->_NumColorDrawBuffers == 1) { - struct st_renderbuffer *rbRead, *rbDraw; - GLint drawX, drawY; - - /* - * Clip the read region against the src buffer bounds. - * We'll still allocate a temporary buffer/texture for the original - * src region size but we'll only read the region which is on-screen. - * This may mean that we draw garbage pixels into the dest region, but - * that's expected. - */ - readX = srcx; - readY = srcy; - readW = width; - readH = height; - pack = ctx->DefaultPacking; - if (!_mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack)) - return GL_TRUE; /* all done */ - - /* clip against dest buffer bounds and scissor box */ - drawX = dstx + pack.SkipPixels; - drawY = dsty + pack.SkipRows; - unpack = pack; - if (!_mesa_clip_drawpixels(ctx, &drawX, &drawY, &readW, &readH, &unpack)) - return GL_TRUE; /* all done */ - - readX = readX - pack.SkipPixels + unpack.SkipPixels; - readY = readY - pack.SkipRows + unpack.SkipRows; - - rbRead = st_get_color_read_renderbuffer(ctx); - rbDraw = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); - - if ((rbRead != rbDraw || - !regions_overlap(readX, readY, drawX, drawY, readW, readH)) && - rbRead->Base.Format == rbDraw->Base.Format) { - struct pipe_box srcBox; - - /* flip src/dst position if needed */ - if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { - /* both buffers will have the same orientation */ - readY = ctx->ReadBuffer->Height - readY - readH; - drawY = ctx->DrawBuffer->Height - drawY - readH; - } - - u_box_2d(readX, readY, readW, readH, &srcBox); - - pipe->resource_copy_region(pipe, - rbDraw->texture, 0, drawX, drawY, 0, - rbRead->texture, 0, &srcBox); - return GL_TRUE; - } - } - - return GL_FALSE; -} - - -static void -st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, - GLsizei width, GLsizei height, - GLint dstx, GLint dsty, GLenum type) -{ - struct st_context *st = st_context(ctx); - struct pipe_context *pipe = st->pipe; - struct pipe_screen *screen = pipe->screen; - struct st_renderbuffer *rbRead; - void *driver_vp, *driver_fp; - struct pipe_resource *pt; - struct pipe_sampler_view *sv[2]; - int num_sampler_view = 1; - GLfloat *color; - enum pipe_format srcFormat, texFormat; - GLboolean invertTex = GL_FALSE; - GLint readX, readY, readW, readH; - GLuint sample_count; - struct gl_pixelstore_attrib pack = ctx->DefaultPacking; - struct st_fp_variant *fpv; - - st_validate_state(st); - - if (type == GL_STENCIL) { - /* can't use texturing to do stencil */ - copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty); - return; - } - - if (blit_copy_pixels(ctx, srcx, srcy, width, height, dstx, dsty, type)) - return; - - /* - * The subsequent code implements glCopyPixels by copying the source - * pixels into a temporary texture that's then applied to a textured quad. - * When we draw the textured quad, all the usual per-fragment operations - * are handled. - */ - - - /* - * Get vertex/fragment shaders - */ - if (type == GL_COLOR) { - rbRead = st_get_color_read_renderbuffer(ctx); - color = NULL; - - fpv = get_color_fp_variant(st); - driver_fp = fpv->driver_shader; - - driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); - - if (st->pixel_xfer.pixelmap_enabled) { - sv[1] = st->pixel_xfer.pixelmap_sampler_view; - num_sampler_view++; - } - } - else { - assert(type == GL_DEPTH); - rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer); - color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; - - fpv = get_depth_stencil_fp_variant(st, GL_TRUE, GL_FALSE); - driver_fp = fpv->driver_shader; - - driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); - } - - /* update fragment program constants */ - st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT); - - - if (rbRead->Base.Wrapped) - rbRead = st_renderbuffer(rbRead->Base.Wrapped); - - sample_count = rbRead->texture->nr_samples; - /* I believe this would be legal, presumably would need to do a resolve - for color, and for depth/stencil spec says to just use one of the - depth/stencil samples per pixel? Need some transfer clarifications. */ - assert(sample_count < 2); - - srcFormat = rbRead->texture->format; - - if (screen->is_format_supported(screen, srcFormat, st->internal_target, - sample_count, - PIPE_BIND_SAMPLER_VIEW)) { - texFormat = srcFormat; - } - else { - /* srcFormat can't be used as a texture format */ - if (type == GL_DEPTH) { - texFormat = st_choose_format(screen, GL_DEPTH_COMPONENT, - st->internal_target, sample_count, - PIPE_BIND_DEPTH_STENCIL); - assert(texFormat != PIPE_FORMAT_NONE); - } - else { - /* default color format */ - texFormat = st_choose_format(screen, GL_RGBA, st->internal_target, - sample_count, PIPE_BIND_SAMPLER_VIEW); - assert(texFormat != PIPE_FORMAT_NONE); - } - } - - /* Invert src region if needed */ - if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { - srcy = ctx->ReadBuffer->Height - srcy - height; - invertTex = !invertTex; - } - - /* Clip the read region against the src buffer bounds. - * We'll still allocate a temporary buffer/texture for the original - * src region size but we'll only read the region which is on-screen. - * This may mean that we draw garbage pixels into the dest region, but - * that's expected. - */ - readX = srcx; - readY = srcy; - readW = width; - readH = height; - _mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack); - readW = MAX2(0, readW); - readH = MAX2(0, readH); - - /* alloc temporary texture */ - pt = alloc_texture(st, width, height, texFormat); - if (!pt) - return; - - sv[0] = st_create_texture_sampler_view(st->pipe, pt); - if (!sv[0]) { - pipe_resource_reference(&pt, NULL); - return; - } - - /* Make temporary texture which is a copy of the src region. - */ - if (srcFormat == texFormat) { - struct pipe_box src_box; - u_box_2d(readX, readY, readW, readH, &src_box); - /* copy source framebuffer surface into mipmap/texture */ - pipe->resource_copy_region(pipe, - pt, /* dest tex */ - 0, - pack.SkipPixels, pack.SkipRows, 0, /* dest pos */ - rbRead->texture, /* src tex */ - 0, - &src_box); - - } - else { - /* CPU-based fallback/conversion */ - struct pipe_transfer *ptRead = - pipe_get_transfer(st->pipe, rbRead->texture, - 0, 0, /* level, layer */ - PIPE_TRANSFER_READ, - readX, readY, readW, readH); - struct pipe_transfer *ptTex; - enum pipe_transfer_usage transfer_usage; - - if (ST_DEBUG & DEBUG_FALLBACK) - debug_printf("%s: fallback processing\n", __FUNCTION__); - - if (type == GL_DEPTH && util_format_is_depth_and_stencil(pt->format)) - transfer_usage = PIPE_TRANSFER_READ_WRITE; - else - transfer_usage = PIPE_TRANSFER_WRITE; - - ptTex = pipe_get_transfer(st->pipe, pt, 0, 0, transfer_usage, - 0, 0, width, height); - - /* copy image from ptRead surface to ptTex surface */ - if (type == GL_COLOR) { - /* alternate path using get/put_tile() */ - GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); - enum pipe_format readFormat, drawFormat; - readFormat = util_format_linear(rbRead->texture->format); - drawFormat = util_format_linear(pt->format); - pipe_get_tile_rgba_format(pipe, ptRead, 0, 0, readW, readH, - readFormat, buf); - pipe_put_tile_rgba_format(pipe, ptTex, pack.SkipPixels, pack.SkipRows, - readW, readH, drawFormat, buf); - free(buf); - } - else { - /* GL_DEPTH */ - GLuint *buf = (GLuint *) malloc(width * height * sizeof(GLuint)); - pipe_get_tile_z(pipe, ptRead, 0, 0, readW, readH, buf); - pipe_put_tile_z(pipe, ptTex, pack.SkipPixels, pack.SkipRows, - readW, readH, buf); - free(buf); - } - - pipe->transfer_destroy(pipe, ptRead); - pipe->transfer_destroy(pipe, ptTex); - } - - /* OK, the texture 'pt' contains the src image/pixels. Now draw a - * textured quad with that texture. - */ - draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2], - width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, - sv, - num_sampler_view, - driver_vp, - driver_fp, - color, invertTex, GL_FALSE, GL_FALSE); - - pipe_resource_reference(&pt, NULL); - pipe_sampler_view_reference(&sv[0], NULL); -} - - - -void st_init_drawpixels_functions(struct dd_function_table *functions) -{ - functions->DrawPixels = st_DrawPixels; - functions->CopyPixels = st_CopyPixels; -} - - -void -st_destroy_drawpix(struct st_context *st) -{ - GLuint i; - - for (i = 0; i < Elements(st->drawpix.shaders); i++) { - if (st->drawpix.shaders[i]) - _mesa_reference_fragprog(st->ctx, &st->drawpix.shaders[i], NULL); - } - - st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL); - if (st->drawpix.vert_shaders[0]) - ureg_free_tokens(st->drawpix.vert_shaders[0]); - if (st->drawpix.vert_shaders[1]) - ureg_free_tokens(st->drawpix.vert_shaders[1]); -} - -#endif /* FEATURE_drawpix */ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Brian Paul + */ + +#include "main/imports.h" +#include "main/image.h" +#include "main/bufferobj.h" +#include "main/macros.h" +#include "main/mfeatures.h" +#include "main/mtypes.h" +#include "main/pack.h" +#include "main/pbo.h" +#include "main/texformat.h" +#include "main/texstore.h" +#include "program/program.h" +#include "program/prog_print.h" +#include "program/prog_instruction.h" + +#include "st_atom.h" +#include "st_atom_constbuf.h" +#include "st_cb_drawpixels.h" +#include "st_cb_readpixels.h" +#include "st_cb_fbo.h" +#include "st_context.h" +#include "st_debug.h" +#include "st_format.h" +#include "st_program.h" +#include "st_texture.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "tgsi/tgsi_ureg.h" +#include "util/u_draw_quad.h" +#include "util/u_format.h" +#include "util/u_inlines.h" +#include "util/u_math.h" +#include "util/u_tile.h" +#include "cso_cache/cso_context.h" + + +#if FEATURE_drawpix + +/** + * Check if the given program is: + * 0: MOVE result.color, fragment.color; + * 1: END; + */ +static GLboolean +is_passthrough_program(const struct gl_fragment_program *prog) +{ + if (prog->Base.NumInstructions == 2) { + const struct prog_instruction *inst = prog->Base.Instructions; + if (inst[0].Opcode == OPCODE_MOV && + inst[1].Opcode == OPCODE_END && + inst[0].DstReg.File == PROGRAM_OUTPUT && + inst[0].DstReg.Index == FRAG_RESULT_COLOR && + inst[0].DstReg.WriteMask == WRITEMASK_XYZW && + inst[0].SrcReg[0].File == PROGRAM_INPUT && + inst[0].SrcReg[0].Index == FRAG_ATTRIB_COL0 && + inst[0].SrcReg[0].Swizzle == SWIZZLE_XYZW) { + return GL_TRUE; + } + } + return GL_FALSE; +} + + + +/** + * Make fragment shader for glDraw/CopyPixels. This shader is made + * by combining the pixel transfer shader with the user-defined shader. + * \param fpIn the current/incoming fragment program + * \param fpOut returns the combined fragment program + */ +void +st_make_drawpix_fragment_program(struct st_context *st, + struct gl_fragment_program *fpIn, + struct gl_fragment_program **fpOut) +{ + struct gl_program *newProg; + + if (is_passthrough_program(fpIn)) { + newProg = (struct gl_program *) _mesa_clone_fragment_program(st->ctx, + &st->pixel_xfer.program->Base); + } + else { +#if 0 + /* debug */ + printf("Base program:\n"); + _mesa_print_program(&fpIn->Base); + printf("DrawPix program:\n"); + _mesa_print_program(&st->pixel_xfer.program->Base.Base); +#endif + newProg = _mesa_combine_programs(st->ctx, + &st->pixel_xfer.program->Base.Base, + &fpIn->Base); + } + +#if 0 + /* debug */ + printf("Combined DrawPixels program:\n"); + _mesa_print_program(newProg); + printf("InputsRead: 0x%x\n", newProg->InputsRead); + printf("OutputsWritten: 0x%x\n", newProg->OutputsWritten); + _mesa_print_parameter_list(newProg->Parameters); +#endif + + *fpOut = (struct gl_fragment_program *) newProg; +} + + +/** + * Create fragment program that does a TEX() instruction to get a Z and/or + * stencil value value, then writes to FRAG_RESULT_DEPTH/FRAG_RESULT_STENCIL. + * Used for glDrawPixels(GL_DEPTH_COMPONENT / GL_STENCIL_INDEX). + * Pass fragment color through as-is. + * \return pointer to the gl_fragment program + */ +struct gl_fragment_program * +st_make_drawpix_z_stencil_program(struct st_context *st, + GLboolean write_depth, + GLboolean write_stencil) +{ + struct gl_context *ctx = st->ctx; + struct gl_program *p; + struct gl_fragment_program *fp; + GLuint ic = 0; + const GLuint shaderIndex = write_depth * 2 + write_stencil; + + assert(shaderIndex < Elements(st->drawpix.shaders)); + + if (st->drawpix.shaders[shaderIndex]) { + /* already have the proper shader */ + return st->drawpix.shaders[shaderIndex]; + } + + /* + * Create shader now + */ + p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); + if (!p) + return NULL; + + p->NumInstructions = write_depth ? 2 : 1; + p->NumInstructions += write_stencil ? 1 : 0; + + p->Instructions = _mesa_alloc_instructions(p->NumInstructions); + if (!p->Instructions) { + ctx->Driver.DeleteProgram(ctx, p); + return NULL; + } + _mesa_init_instructions(p->Instructions, p->NumInstructions); + + if (write_depth) { + /* TEX result.depth, fragment.texcoord[0], texture[0], 2D; */ + p->Instructions[ic].Opcode = OPCODE_TEX; + p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; + p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPTH; + p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z; + p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; + p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; + p->Instructions[ic].TexSrcUnit = 0; + p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; + ic++; + } + + if (write_stencil) { + /* TEX result.stencil, fragment.texcoord[0], texture[0], 2D; */ + p->Instructions[ic].Opcode = OPCODE_TEX; + p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; + p->Instructions[ic].DstReg.Index = FRAG_RESULT_STENCIL; + p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Y; + p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; + p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; + p->Instructions[ic].TexSrcUnit = 1; + p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; + ic++; + } + + /* END; */ + p->Instructions[ic++].Opcode = OPCODE_END; + + assert(ic == p->NumInstructions); + + p->InputsRead = FRAG_BIT_TEX0 | FRAG_BIT_COL0; + p->OutputsWritten = 0; + if (write_depth) + p->OutputsWritten |= BITFIELD64_BIT(FRAG_RESULT_DEPTH); + if (write_stencil) + p->OutputsWritten |= BITFIELD64_BIT(FRAG_RESULT_STENCIL); + + p->SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */ + if (write_stencil) + p->SamplersUsed |= 1 << 1; + + fp = (struct gl_fragment_program *) p; + + /* save the new shader */ + st->drawpix.shaders[shaderIndex] = fp; + + return fp; +} + + +/** + * Create a simple vertex shader that just passes through the + * vertex position and texcoord (and optionally, color). + */ +static void * +make_passthrough_vertex_shader(struct st_context *st, + GLboolean passColor) +{ + if (!st->drawpix.vert_shaders[passColor]) { + struct ureg_program *ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); + + if (ureg == NULL) + return NULL; + + /* MOV result.pos, vertex.pos; */ + ureg_MOV(ureg, + ureg_DECL_output( ureg, TGSI_SEMANTIC_POSITION, 0 ), + ureg_DECL_vs_input( ureg, 0 )); + + /* MOV result.texcoord0, vertex.attr[1]; */ + ureg_MOV(ureg, + ureg_DECL_output( ureg, TGSI_SEMANTIC_GENERIC, 0 ), + ureg_DECL_vs_input( ureg, 1 )); + + if (passColor) { + /* MOV result.color0, vertex.attr[2]; */ + ureg_MOV(ureg, + ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, 0 ), + ureg_DECL_vs_input( ureg, 2 )); + } + + ureg_END( ureg ); + + st->drawpix.vert_shaders[passColor] = + ureg_create_shader_and_destroy( ureg, st->pipe ); + } + + return st->drawpix.vert_shaders[passColor]; +} + + +/** + * Return a texture base format for drawing/copying an image + * of the given format. + */ +static GLenum +base_format(GLenum format) +{ + switch (format) { + case GL_DEPTH_COMPONENT: + return GL_DEPTH_COMPONENT; + case GL_DEPTH_STENCIL: + return GL_DEPTH_STENCIL; + case GL_STENCIL_INDEX: + return GL_STENCIL_INDEX; + default: + return GL_RGBA; + } +} + + +/** + * Return a texture internalFormat for drawing/copying an image + * of the given format and type. + */ +static GLenum +internal_format(struct gl_context *ctx, GLenum format, GLenum type) +{ + switch (format) { + case GL_DEPTH_COMPONENT: + return GL_DEPTH_COMPONENT; + case GL_DEPTH_STENCIL: + return GL_DEPTH_STENCIL; + case GL_STENCIL_INDEX: + return GL_STENCIL_INDEX; + default: + if (_mesa_is_integer_format(format)) { + switch (type) { + case GL_BYTE: + return GL_RGBA8I; + case GL_UNSIGNED_BYTE: + return GL_RGBA8UI; + case GL_SHORT: + return GL_RGBA16I; + case GL_UNSIGNED_SHORT: + return GL_RGBA16UI; + case GL_INT: + return GL_RGBA32I; + case GL_UNSIGNED_INT: + return GL_RGBA32UI; + default: + assert(0 && "Unexpected type in internal_format()"); + return GL_RGBA_INTEGER; + } + } + else { + switch (type) { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + default: + return GL_RGBA8; + + case GL_UNSIGNED_BYTE_3_3_2: + case GL_UNSIGNED_BYTE_2_3_3_REV: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + return GL_RGBA4; + + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_5_6_5_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + return GL_RGB5_A1; + + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + return GL_RGB10_A2; + + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_INT: + return GL_RGBA16; + + case GL_BYTE: + return + ctx->Extensions.EXT_texture_snorm ? GL_RGBA8_SNORM : GL_RGBA8; + + case GL_SHORT: + case GL_INT: + return + ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16; + + case GL_HALF_FLOAT_ARB: + return + ctx->Extensions.ARB_texture_float ? GL_RGBA16F : + ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16; + + case GL_FLOAT: + case GL_DOUBLE: + return + ctx->Extensions.ARB_texture_float ? GL_RGBA32F : + ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16; + + case GL_UNSIGNED_INT_5_9_9_9_REV: + assert(ctx->Extensions.EXT_texture_shared_exponent); + return GL_RGB9_E5; + + case GL_UNSIGNED_INT_10F_11F_11F_REV: + assert(ctx->Extensions.EXT_packed_float); + return GL_R11F_G11F_B10F; + } + } + } +} + + +/** + * Create a temporary texture to hold an image of the given size. + * If width, height are not POT and the driver only handles POT textures, + * allocate the next larger size of texture that is POT. + */ +static struct pipe_resource * +alloc_texture(struct st_context *st, GLsizei width, GLsizei height, + enum pipe_format texFormat) +{ + struct pipe_resource *pt; + + pt = st_texture_create(st, st->internal_target, texFormat, 0, + width, height, 1, 1, PIPE_BIND_SAMPLER_VIEW); + + return pt; +} + + +/** + * Make texture containing an image for glDrawPixels image. + * If 'pixels' is NULL, leave the texture image data undefined. + */ +static struct pipe_resource * +make_texture(struct st_context *st, + GLsizei width, GLsizei height, GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels) +{ + struct gl_context *ctx = st->ctx; + struct pipe_context *pipe = st->pipe; + gl_format mformat; + struct pipe_resource *pt; + enum pipe_format pipeFormat; + GLenum baseFormat, intFormat; + + baseFormat = base_format(format); + intFormat = internal_format(ctx, format, type); + + mformat = st_ChooseTextureFormat_renderable(ctx, intFormat, + format, type, GL_FALSE); + assert(mformat); + + pipeFormat = st_mesa_format_to_pipe_format(mformat); + assert(pipeFormat); + + pixels = _mesa_map_pbo_source(ctx, unpack, pixels); + if (!pixels) + return NULL; + + /* alloc temporary texture */ + pt = alloc_texture(st, width, height, pipeFormat); + if (!pt) { + _mesa_unmap_pbo_source(ctx, unpack); + return NULL; + } + + { + struct pipe_transfer *transfer; + static const GLuint dstImageOffsets = 0; + GLboolean success; + GLubyte *dest; + const GLbitfield imageTransferStateSave = ctx->_ImageTransferState; + + /* we'll do pixel transfer in a fragment shader */ + ctx->_ImageTransferState = 0x0; + + transfer = pipe_get_transfer(st->pipe, pt, 0, 0, + PIPE_TRANSFER_WRITE, 0, 0, + width, height); + + /* map texture transfer */ + dest = pipe_transfer_map(pipe, transfer); + + + /* Put image into texture transfer. + * Note that the image is actually going to be upside down in + * the texture. We deal with that with texcoords. + */ + success = _mesa_texstore(ctx, 2, /* dims */ + baseFormat, /* baseInternalFormat */ + mformat, /* gl_format */ + dest, /* dest */ + 0, 0, 0, /* dstX/Y/Zoffset */ + transfer->stride, /* dstRowStride, bytes */ + &dstImageOffsets, /* dstImageOffsets */ + width, height, 1, /* size */ + format, type, /* src format/type */ + pixels, /* data source */ + unpack); + + /* unmap */ + pipe_transfer_unmap(pipe, transfer); + pipe->transfer_destroy(pipe, transfer); + + assert(success); + + /* restore */ + ctx->_ImageTransferState = imageTransferStateSave; + } + + _mesa_unmap_pbo_source(ctx, unpack); + + return pt; +} + + +/** + * Draw quad with texcoords and optional color. + * Coords are gallium window coords with y=0=top. + * \param color may be null + * \param invertTex if true, flip texcoords vertically + */ +static void +draw_quad(struct gl_context *ctx, GLfloat x0, GLfloat y0, GLfloat z, + GLfloat x1, GLfloat y1, const GLfloat *color, + GLboolean invertTex, GLfloat maxXcoord, GLfloat maxYcoord) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */ + + /* setup vertex data */ + { + const struct gl_framebuffer *fb = st->ctx->DrawBuffer; + const GLfloat fb_width = (GLfloat) fb->Width; + const GLfloat fb_height = (GLfloat) fb->Height; + const GLfloat clip_x0 = x0 / fb_width * 2.0f - 1.0f; + const GLfloat clip_y0 = y0 / fb_height * 2.0f - 1.0f; + const GLfloat clip_x1 = x1 / fb_width * 2.0f - 1.0f; + const GLfloat clip_y1 = y1 / fb_height * 2.0f - 1.0f; + const GLfloat sLeft = 0.0f, sRight = maxXcoord; + const GLfloat tTop = invertTex ? maxYcoord : 0.0f; + const GLfloat tBot = invertTex ? 0.0f : maxYcoord; + GLuint i; + + /* upper-left */ + verts[0][0][0] = clip_x0; /* v[0].attr[0].x */ + verts[0][0][1] = clip_y0; /* v[0].attr[0].y */ + + /* upper-right */ + verts[1][0][0] = clip_x1; + verts[1][0][1] = clip_y0; + + /* lower-right */ + verts[2][0][0] = clip_x1; + verts[2][0][1] = clip_y1; + + /* lower-left */ + verts[3][0][0] = clip_x0; + verts[3][0][1] = clip_y1; + + verts[0][1][0] = sLeft; /* v[0].attr[1].S */ + verts[0][1][1] = tTop; /* v[0].attr[1].T */ + verts[1][1][0] = sRight; + verts[1][1][1] = tTop; + verts[2][1][0] = sRight; + verts[2][1][1] = tBot; + verts[3][1][0] = sLeft; + verts[3][1][1] = tBot; + + /* same for all verts: */ + if (color) { + for (i = 0; i < 4; i++) { + verts[i][0][2] = z; /* v[i].attr[0].z */ + verts[i][0][3] = 1.0f; /* v[i].attr[0].w */ + verts[i][2][0] = color[0]; /* v[i].attr[2].r */ + verts[i][2][1] = color[1]; /* v[i].attr[2].g */ + verts[i][2][2] = color[2]; /* v[i].attr[2].b */ + verts[i][2][3] = color[3]; /* v[i].attr[2].a */ + verts[i][1][2] = 0.0f; /* v[i].attr[1].R */ + verts[i][1][3] = 1.0f; /* v[i].attr[1].Q */ + } + } + else { + for (i = 0; i < 4; i++) { + verts[i][0][2] = z; /*Z*/ + verts[i][0][3] = 1.0f; /*W*/ + verts[i][1][2] = 0.0f; /*R*/ + verts[i][1][3] = 1.0f; /*Q*/ + } + } + } + + { + struct pipe_resource *buf; + + /* allocate/load buffer object with vertex data */ + buf = pipe_buffer_create(pipe->screen, + PIPE_BIND_VERTEX_BUFFER, + PIPE_USAGE_STATIC, + sizeof(verts)); + pipe_buffer_write(st->pipe, buf, 0, sizeof(verts), verts); + + util_draw_vertex_buffer(pipe, st->cso_context, buf, 0, + PIPE_PRIM_QUADS, + 4, /* verts */ + 3); /* attribs/vert */ + pipe_resource_reference(&buf, NULL); + } +} + + + +static void +draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, + GLsizei width, GLsizei height, + GLfloat zoomX, GLfloat zoomY, + struct pipe_sampler_view **sv, + int num_sampler_view, + void *driver_vp, + void *driver_fp, + const GLfloat *color, + GLboolean invertTex, + GLboolean write_depth, GLboolean write_stencil) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct cso_context *cso = st->cso_context; + GLfloat x0, y0, x1, y1; + GLsizei maxSize; + boolean normalized = sv[0]->texture->target != PIPE_TEXTURE_RECT; + + /* limit checks */ + /* XXX if DrawPixels image is larger than max texture size, break + * it up into chunks. + */ + maxSize = 1 << (pipe->screen->get_param(pipe->screen, + PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); + assert(width <= maxSize); + assert(height <= maxSize); + + cso_save_rasterizer(cso); + cso_save_viewport(cso); + cso_save_samplers(cso); + cso_save_fragment_sampler_views(cso); + cso_save_fragment_shader(cso); + cso_save_vertex_shader(cso); + cso_save_vertex_elements(cso); + cso_save_vertex_buffers(cso); + if (write_stencil) { + cso_save_depth_stencil_alpha(cso); + cso_save_blend(cso); + } + + /* rasterizer state: just scissor */ + { + struct pipe_rasterizer_state rasterizer; + memset(&rasterizer, 0, sizeof(rasterizer)); + rasterizer.clamp_fragment_color = ctx->Color._ClampFragmentColor; + rasterizer.gl_rasterization_rules = 1; + rasterizer.scissor = ctx->Scissor.Enabled; + cso_set_rasterizer(cso, &rasterizer); + } + + if (write_stencil) { + /* Stencil writing bypasses the normal fragment pipeline to + * disable color writing and set stencil test to always pass. + */ + struct pipe_depth_stencil_alpha_state dsa; + struct pipe_blend_state blend; + + /* depth/stencil */ + memset(&dsa, 0, sizeof(dsa)); + dsa.stencil[0].enabled = 1; + dsa.stencil[0].func = PIPE_FUNC_ALWAYS; + dsa.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff; + dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; + if (write_depth) { + /* writing depth+stencil: depth test always passes */ + dsa.depth.enabled = 1; + dsa.depth.writemask = ctx->Depth.Mask; + dsa.depth.func = PIPE_FUNC_ALWAYS; + } + cso_set_depth_stencil_alpha(cso, &dsa); + + /* blend (colormask) */ + memset(&blend, 0, sizeof(blend)); + cso_set_blend(cso, &blend); + } + + /* fragment shader state: TEX lookup program */ + cso_set_fragment_shader_handle(cso, driver_fp); + + /* vertex shader state: position + texcoord pass-through */ + cso_set_vertex_shader_handle(cso, driver_vp); + + + /* texture sampling state: */ + { + struct pipe_sampler_state sampler; + memset(&sampler, 0, sizeof(sampler)); + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP; + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP; + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP; + sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.normalized_coords = normalized; + + cso_single_sampler(cso, 0, &sampler); + if (num_sampler_view > 1) { + cso_single_sampler(cso, 1, &sampler); + } + cso_single_sampler_done(cso); + } + + /* viewport state: viewport matching window dims */ + { + const float w = (float) ctx->DrawBuffer->Width; + const float h = (float) ctx->DrawBuffer->Height; + struct pipe_viewport_state vp; + vp.scale[0] = 0.5f * w; + vp.scale[1] = -0.5f * h; + vp.scale[2] = 0.5f; + vp.scale[3] = 1.0f; + vp.translate[0] = 0.5f * w; + vp.translate[1] = 0.5f * h; + vp.translate[2] = 0.5f; + vp.translate[3] = 0.0f; + cso_set_viewport(cso, &vp); + } + + cso_set_vertex_elements(cso, 3, st->velems_util_draw); + + /* texture state: */ + cso_set_fragment_sampler_views(cso, num_sampler_view, sv); + + /* Compute Gallium window coords (y=0=top) with pixel zoom. + * Recall that these coords are transformed by the current + * vertex shader and viewport transformation. + */ + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM) { + y = ctx->DrawBuffer->Height - (int) (y + height * ctx->Pixel.ZoomY); + invertTex = !invertTex; + } + + x0 = (GLfloat) x; + x1 = x + width * ctx->Pixel.ZoomX; + y0 = (GLfloat) y; + y1 = y + height * ctx->Pixel.ZoomY; + + /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */ + z = z * 2.0 - 1.0; + + draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex, + normalized ? ((GLfloat) width / sv[0]->texture->width0) : (GLfloat)width, + normalized ? ((GLfloat) height / sv[0]->texture->height0) : (GLfloat)height); + + /* restore state */ + cso_restore_rasterizer(cso); + cso_restore_viewport(cso); + cso_restore_samplers(cso); + cso_restore_fragment_sampler_views(cso); + cso_restore_fragment_shader(cso); + cso_restore_vertex_shader(cso); + cso_restore_vertex_elements(cso); + cso_restore_vertex_buffers(cso); + if (write_stencil) { + cso_restore_depth_stencil_alpha(cso); + cso_restore_blend(cso); + } +} + + +/** + * Software fallback to do glDrawPixels(GL_STENCIL_INDEX) when we + * can't use a fragment shader to write stencil values. + */ +static void +draw_stencil_pixels(struct gl_context *ctx, GLint x, GLint y, + GLsizei width, GLsizei height, GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct st_renderbuffer *strb; + enum pipe_transfer_usage usage; + struct pipe_transfer *pt; + const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; + GLint skipPixels; + ubyte *stmap; + struct gl_pixelstore_attrib clippedUnpack = *unpack; + + if (!zoom) { + if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height, + &clippedUnpack)) { + /* totally clipped */ + return; + } + } + + strb = st_renderbuffer(ctx->DrawBuffer-> + Attachment[BUFFER_STENCIL].Renderbuffer); + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + y = ctx->DrawBuffer->Height - y - height; + } + + if(format != GL_DEPTH_STENCIL && + util_format_get_component_bits(strb->format, + UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) + usage = PIPE_TRANSFER_READ_WRITE; + else + usage = PIPE_TRANSFER_WRITE; + + pt = pipe_get_transfer(st_context(ctx)->pipe, strb->texture, 0, 0, + usage, x, y, + width, height); + + stmap = pipe_transfer_map(pipe, pt); + + pixels = _mesa_map_pbo_source(ctx, &clippedUnpack, pixels); + assert(pixels); + + /* if width > MAX_WIDTH, have to process image in chunks */ + skipPixels = 0; + while (skipPixels < width) { + const GLint spanX = skipPixels; + const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); + GLint row; + for (row = 0; row < height; row++) { + GLubyte sValues[MAX_WIDTH]; + GLuint zValues[MAX_WIDTH]; + GLenum destType = GL_UNSIGNED_BYTE; + const GLvoid *source = _mesa_image_address2d(&clippedUnpack, pixels, + width, height, + format, type, + row, skipPixels); + _mesa_unpack_stencil_span(ctx, spanWidth, destType, sValues, + type, source, &clippedUnpack, + ctx->_ImageTransferState); + + if (format == GL_DEPTH_STENCIL) { + _mesa_unpack_depth_span(ctx, spanWidth, GL_UNSIGNED_INT, zValues, + (1 << 24) - 1, type, source, + &clippedUnpack); + } + + if (zoom) { + _mesa_problem(ctx, "Gallium glDrawPixels(GL_STENCIL) with " + "zoom not complete"); + } + + { + GLint spanY; + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + spanY = height - row - 1; + } + else { + spanY = row; + } + + /* now pack the stencil (and Z) values in the dest format */ + switch (pt->resource->format) { + case PIPE_FORMAT_S8_USCALED: + { + ubyte *dest = stmap + spanY * pt->stride + spanX; + assert(usage == PIPE_TRANSFER_WRITE); + memcpy(dest, sValues, spanWidth); + } + break; + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + if (format == GL_DEPTH_STENCIL) { + uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); + GLint k; + assert(usage == PIPE_TRANSFER_WRITE); + for (k = 0; k < spanWidth; k++) { + dest[k] = zValues[k] | (sValues[k] << 24); + } + } + else { + uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); + GLint k; + assert(usage == PIPE_TRANSFER_READ_WRITE); + for (k = 0; k < spanWidth; k++) { + dest[k] = (dest[k] & 0xffffff) | (sValues[k] << 24); + } + } + break; + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + if (format == GL_DEPTH_STENCIL) { + uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); + GLint k; + assert(usage == PIPE_TRANSFER_WRITE); + for (k = 0; k < spanWidth; k++) { + dest[k] = (zValues[k] << 8) | (sValues[k] & 0xff); + } + } + else { + uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); + GLint k; + assert(usage == PIPE_TRANSFER_READ_WRITE); + for (k = 0; k < spanWidth; k++) { + dest[k] = (dest[k] & 0xffffff00) | (sValues[k] & 0xff); + } + } + break; + default: + assert(0); + } + } + } + skipPixels += spanWidth; + } + + _mesa_unmap_pbo_source(ctx, &clippedUnpack); + + /* unmap the stencil buffer */ + pipe_transfer_unmap(pipe, pt); + pipe->transfer_destroy(pipe, pt); +} + + +/** + * Get fragment program variant for a glDrawPixels or glCopyPixels + * command for RGBA data. + */ +static struct st_fp_variant * +get_color_fp_variant(struct st_context *st) +{ + struct gl_context *ctx = st->ctx; + struct st_fp_variant_key key; + struct st_fp_variant *fpv; + + memset(&key, 0, sizeof(key)); + + key.st = st; + key.drawpixels = 1; + key.scaleAndBias = (ctx->Pixel.RedBias != 0.0 || + ctx->Pixel.RedScale != 1.0 || + ctx->Pixel.GreenBias != 0.0 || + ctx->Pixel.GreenScale != 1.0 || + ctx->Pixel.BlueBias != 0.0 || + ctx->Pixel.BlueScale != 1.0 || + ctx->Pixel.AlphaBias != 0.0 || + ctx->Pixel.AlphaScale != 1.0); + key.pixelMaps = ctx->Pixel.MapColorFlag; + + fpv = st_get_fp_variant(st, st->fp, &key); + + return fpv; +} + + +/** + * Get fragment program variant for a glDrawPixels or glCopyPixels + * command for depth/stencil data. + */ +static struct st_fp_variant * +get_depth_stencil_fp_variant(struct st_context *st, GLboolean write_depth, + GLboolean write_stencil) +{ + struct st_fp_variant_key key; + struct st_fp_variant *fpv; + + memset(&key, 0, sizeof(key)); + + key.st = st; + key.drawpixels = 1; + key.drawpixels_z = write_depth; + key.drawpixels_stencil = write_stencil; + + fpv = st_get_fp_variant(st, st->fp, &key); + + return fpv; +} + + +/** + * Called via ctx->Driver.DrawPixels() + */ +static void +st_DrawPixels(struct gl_context *ctx, GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) +{ + void *driver_vp, *driver_fp; + struct st_context *st = st_context(ctx); + const GLfloat *color; + struct pipe_context *pipe = st->pipe; + GLboolean write_stencil = GL_FALSE, write_depth = GL_FALSE; + struct pipe_sampler_view *sv[2]; + int num_sampler_view = 1; + enum pipe_format stencil_format = PIPE_FORMAT_NONE; + struct st_fp_variant *fpv; + + if (format == GL_DEPTH_STENCIL) + write_stencil = write_depth = GL_TRUE; + else if (format == GL_STENCIL_INDEX) + write_stencil = GL_TRUE; + else if (format == GL_DEPTH_COMPONENT) + write_depth = GL_TRUE; + + if (write_stencil) { + enum pipe_format tex_format; + /* can we write to stencil if not fallback */ + if (!pipe->screen->get_param(pipe->screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) + goto stencil_fallback; + + tex_format = st_choose_format(st->pipe->screen, base_format(format), + PIPE_TEXTURE_2D, + 0, PIPE_BIND_SAMPLER_VIEW); + if (tex_format == PIPE_FORMAT_Z24_UNORM_S8_USCALED) + stencil_format = PIPE_FORMAT_X24S8_USCALED; + else if (tex_format == PIPE_FORMAT_S8_USCALED_Z24_UNORM) + stencil_format = PIPE_FORMAT_S8X24_USCALED; + else + stencil_format = PIPE_FORMAT_S8_USCALED; + if (stencil_format == PIPE_FORMAT_NONE) + goto stencil_fallback; + } + + /* Mesa state should be up to date by now */ + assert(ctx->NewState == 0x0); + + st_validate_state(st); + + /* + * Get vertex/fragment shaders + */ + if (write_depth || write_stencil) { + fpv = get_depth_stencil_fp_variant(st, write_depth, write_stencil); + + driver_fp = fpv->driver_shader; + + driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); + + color = ctx->Current.RasterColor; + } + else { + fpv = get_color_fp_variant(st); + + driver_fp = fpv->driver_shader; + + driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); + + color = NULL; + if (st->pixel_xfer.pixelmap_enabled) { + sv[1] = st->pixel_xfer.pixelmap_sampler_view; + num_sampler_view++; + } + } + + /* update fragment program constants */ + st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT); + + /* draw with textured quad */ + { + struct pipe_resource *pt + = make_texture(st, width, height, format, type, unpack, pixels); + if (pt) { + sv[0] = st_create_texture_sampler_view(st->pipe, pt); + + if (sv[0]) { + if (write_stencil) { + sv[1] = st_create_texture_sampler_view_format(st->pipe, pt, + stencil_format); + num_sampler_view++; + } + + draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2], + width, height, + ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, + sv, + num_sampler_view, + driver_vp, + driver_fp, + color, GL_FALSE, write_depth, write_stencil); + pipe_sampler_view_reference(&sv[0], NULL); + if (num_sampler_view > 1) + pipe_sampler_view_reference(&sv[1], NULL); + } + pipe_resource_reference(&pt, NULL); + } + } + return; + +stencil_fallback: + draw_stencil_pixels(ctx, x, y, width, height, format, type, + unpack, pixels); +} + + + +/** + * Software fallback for glCopyPixels(GL_STENCIL). + */ +static void +copy_stencil_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, + GLsizei width, GLsizei height, + GLint dstx, GLint dsty) +{ + struct st_renderbuffer *rbDraw; + struct pipe_context *pipe = st_context(ctx)->pipe; + enum pipe_transfer_usage usage; + struct pipe_transfer *ptDraw; + ubyte *drawMap; + ubyte *buffer; + int i; + + buffer = malloc(width * height * sizeof(ubyte)); + if (!buffer) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)"); + return; + } + + /* Get the dest renderbuffer. If there's a wrapper, use the + * underlying renderbuffer. + */ + rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer); + if (rbDraw->Base.Wrapped) + rbDraw = st_renderbuffer(rbDraw->Base.Wrapped); + + /* this will do stencil pixel transfer ops */ + st_read_stencil_pixels(ctx, srcx, srcy, width, height, + GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, + &ctx->DefaultPacking, buffer); + + if (0) { + /* debug code: dump stencil values */ + GLint row, col; + for (row = 0; row < height; row++) { + printf("%3d: ", row); + for (col = 0; col < width; col++) { + printf("%02x ", buffer[col + row * width]); + } + printf("\n"); + } + } + + if (util_format_get_component_bits(rbDraw->format, + UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) + usage = PIPE_TRANSFER_READ_WRITE; + else + usage = PIPE_TRANSFER_WRITE; + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + dsty = rbDraw->Base.Height - dsty - height; + } + + ptDraw = pipe_get_transfer(st_context(ctx)->pipe, + rbDraw->texture, 0, 0, + usage, dstx, dsty, + width, height); + + assert(util_format_get_blockwidth(ptDraw->resource->format) == 1); + assert(util_format_get_blockheight(ptDraw->resource->format) == 1); + + /* map the stencil buffer */ + drawMap = pipe_transfer_map(pipe, ptDraw); + + /* draw */ + /* XXX PixelZoom not handled yet */ + for (i = 0; i < height; i++) { + ubyte *dst; + const ubyte *src; + int y; + + y = i; + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + y = height - y - 1; + } + + dst = drawMap + y * ptDraw->stride; + src = buffer + i * width; + + switch (ptDraw->resource->format) { + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + { + uint *dst4 = (uint *) dst; + int j; + assert(usage == PIPE_TRANSFER_READ_WRITE); + for (j = 0; j < width; j++) { + *dst4 = (*dst4 & 0xffffff) | (src[j] << 24); + dst4++; + } + } + break; + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + { + uint *dst4 = (uint *) dst; + int j; + assert(usage == PIPE_TRANSFER_READ_WRITE); + for (j = 0; j < width; j++) { + *dst4 = (*dst4 & 0xffffff00) | (src[j] & 0xff); + dst4++; + } + } + break; + case PIPE_FORMAT_S8_USCALED: + assert(usage == PIPE_TRANSFER_WRITE); + memcpy(dst, src, width); + break; + default: + assert(0); + } + } + + free(buffer); + + /* unmap the stencil buffer */ + pipe_transfer_unmap(pipe, ptDraw); + pipe->transfer_destroy(pipe, ptDraw); +} + + +/** Do the src/dest regions overlap? */ +static GLboolean +regions_overlap(GLint srcX, GLint srcY, GLint dstX, GLint dstY, + GLsizei width, GLsizei height) +{ + if (srcX + width <= dstX || + dstX + width <= srcX || + srcY + height <= dstY || + dstY + height <= srcY) + return GL_FALSE; + else + return GL_TRUE; +} + + +/** + * Try to do a glCopyPixels for simple cases with a blit by calling + * pipe->resource_copy_region(). + * + * We can do this when we're copying color pixels (depth/stencil + * eventually) with no pixel zoom, no pixel transfer ops, no + * per-fragment ops, the src/dest regions don't overlap and the + * src/dest pixel formats are the same. + */ +static GLboolean +blit_copy_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, + GLsizei width, GLsizei height, + GLint dstx, GLint dsty, GLenum type) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct gl_pixelstore_attrib pack, unpack; + GLint readX, readY, readW, readH; + + if (type == GL_COLOR && + ctx->Pixel.ZoomX == 1.0 && + ctx->Pixel.ZoomY == 1.0 && + ctx->_ImageTransferState == 0x0 && + !ctx->Color.BlendEnabled && + !ctx->Color.AlphaEnabled && + !ctx->Depth.Test && + !ctx->Fog.Enabled && + !ctx->Stencil.Enabled && + !ctx->FragmentProgram.Enabled && + !ctx->VertexProgram.Enabled && + !ctx->Shader.CurrentFragmentProgram && + st_fb_orientation(ctx->ReadBuffer) == st_fb_orientation(ctx->DrawBuffer) && + ctx->DrawBuffer->_NumColorDrawBuffers == 1) { + struct st_renderbuffer *rbRead, *rbDraw; + GLint drawX, drawY; + + /* + * Clip the read region against the src buffer bounds. + * We'll still allocate a temporary buffer/texture for the original + * src region size but we'll only read the region which is on-screen. + * This may mean that we draw garbage pixels into the dest region, but + * that's expected. + */ + readX = srcx; + readY = srcy; + readW = width; + readH = height; + pack = ctx->DefaultPacking; + if (!_mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack)) + return GL_TRUE; /* all done */ + + /* clip against dest buffer bounds and scissor box */ + drawX = dstx + pack.SkipPixels; + drawY = dsty + pack.SkipRows; + unpack = pack; + if (!_mesa_clip_drawpixels(ctx, &drawX, &drawY, &readW, &readH, &unpack)) + return GL_TRUE; /* all done */ + + readX = readX - pack.SkipPixels + unpack.SkipPixels; + readY = readY - pack.SkipRows + unpack.SkipRows; + + rbRead = st_get_color_read_renderbuffer(ctx); + rbDraw = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); + + if ((rbRead != rbDraw || + !regions_overlap(readX, readY, drawX, drawY, readW, readH)) && + rbRead->Base.Format == rbDraw->Base.Format) { + struct pipe_box srcBox; + + /* flip src/dst position if needed */ + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + /* both buffers will have the same orientation */ + readY = ctx->ReadBuffer->Height - readY - readH; + drawY = ctx->DrawBuffer->Height - drawY - readH; + } + + u_box_2d(readX, readY, readW, readH, &srcBox); + + pipe->resource_copy_region(pipe, + rbDraw->texture, 0, drawX, drawY, 0, + rbRead->texture, 0, &srcBox); + return GL_TRUE; + } + } + + return GL_FALSE; +} + + +static void +st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, + GLsizei width, GLsizei height, + GLint dstx, GLint dsty, GLenum type) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; + struct st_renderbuffer *rbRead; + void *driver_vp, *driver_fp; + struct pipe_resource *pt; + struct pipe_sampler_view *sv[2]; + int num_sampler_view = 1; + GLfloat *color; + enum pipe_format srcFormat, texFormat; + GLboolean invertTex = GL_FALSE; + GLint readX, readY, readW, readH; + GLuint sample_count; + struct gl_pixelstore_attrib pack = ctx->DefaultPacking; + struct st_fp_variant *fpv; + + st_validate_state(st); + + if (type == GL_STENCIL) { + /* can't use texturing to do stencil */ + copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty); + return; + } + + if (blit_copy_pixels(ctx, srcx, srcy, width, height, dstx, dsty, type)) + return; + + /* + * The subsequent code implements glCopyPixels by copying the source + * pixels into a temporary texture that's then applied to a textured quad. + * When we draw the textured quad, all the usual per-fragment operations + * are handled. + */ + + + /* + * Get vertex/fragment shaders + */ + if (type == GL_COLOR) { + rbRead = st_get_color_read_renderbuffer(ctx); + color = NULL; + + fpv = get_color_fp_variant(st); + driver_fp = fpv->driver_shader; + + driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); + + if (st->pixel_xfer.pixelmap_enabled) { + sv[1] = st->pixel_xfer.pixelmap_sampler_view; + num_sampler_view++; + } + } + else { + assert(type == GL_DEPTH); + rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer); + color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; + + fpv = get_depth_stencil_fp_variant(st, GL_TRUE, GL_FALSE); + driver_fp = fpv->driver_shader; + + driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); + } + + /* update fragment program constants */ + st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT); + + + if (rbRead->Base.Wrapped) + rbRead = st_renderbuffer(rbRead->Base.Wrapped); + + sample_count = rbRead->texture->nr_samples; + /* I believe this would be legal, presumably would need to do a resolve + for color, and for depth/stencil spec says to just use one of the + depth/stencil samples per pixel? Need some transfer clarifications. */ + assert(sample_count < 2); + + srcFormat = rbRead->texture->format; + + if (screen->is_format_supported(screen, srcFormat, st->internal_target, + sample_count, + PIPE_BIND_SAMPLER_VIEW)) { + texFormat = srcFormat; + } + else { + /* srcFormat can't be used as a texture format */ + if (type == GL_DEPTH) { + texFormat = st_choose_format(screen, GL_DEPTH_COMPONENT, + st->internal_target, sample_count, + PIPE_BIND_DEPTH_STENCIL); + assert(texFormat != PIPE_FORMAT_NONE); + } + else { + /* default color format */ + texFormat = st_choose_format(screen, GL_RGBA, st->internal_target, + sample_count, PIPE_BIND_SAMPLER_VIEW); + assert(texFormat != PIPE_FORMAT_NONE); + } + } + + /* Invert src region if needed */ + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + srcy = ctx->ReadBuffer->Height - srcy - height; + invertTex = !invertTex; + } + + /* Clip the read region against the src buffer bounds. + * We'll still allocate a temporary buffer/texture for the original + * src region size but we'll only read the region which is on-screen. + * This may mean that we draw garbage pixels into the dest region, but + * that's expected. + */ + readX = srcx; + readY = srcy; + readW = width; + readH = height; + _mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack); + readW = MAX2(0, readW); + readH = MAX2(0, readH); + + /* alloc temporary texture */ + pt = alloc_texture(st, width, height, texFormat); + if (!pt) + return; + + sv[0] = st_create_texture_sampler_view(st->pipe, pt); + if (!sv[0]) { + pipe_resource_reference(&pt, NULL); + return; + } + + /* Make temporary texture which is a copy of the src region. + */ + if (srcFormat == texFormat) { + struct pipe_box src_box; + u_box_2d(readX, readY, readW, readH, &src_box); + /* copy source framebuffer surface into mipmap/texture */ + pipe->resource_copy_region(pipe, + pt, /* dest tex */ + 0, + pack.SkipPixels, pack.SkipRows, 0, /* dest pos */ + rbRead->texture, /* src tex */ + 0, + &src_box); + + } + else { + /* CPU-based fallback/conversion */ + struct pipe_transfer *ptRead = + pipe_get_transfer(st->pipe, rbRead->texture, + 0, 0, /* level, layer */ + PIPE_TRANSFER_READ, + readX, readY, readW, readH); + struct pipe_transfer *ptTex; + enum pipe_transfer_usage transfer_usage; + + if (ST_DEBUG & DEBUG_FALLBACK) + debug_printf("%s: fallback processing\n", __FUNCTION__); + + if (type == GL_DEPTH && util_format_is_depth_and_stencil(pt->format)) + transfer_usage = PIPE_TRANSFER_READ_WRITE; + else + transfer_usage = PIPE_TRANSFER_WRITE; + + ptTex = pipe_get_transfer(st->pipe, pt, 0, 0, transfer_usage, + 0, 0, width, height); + + /* copy image from ptRead surface to ptTex surface */ + if (type == GL_COLOR) { + /* alternate path using get/put_tile() */ + GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); + enum pipe_format readFormat, drawFormat; + readFormat = util_format_linear(rbRead->texture->format); + drawFormat = util_format_linear(pt->format); + pipe_get_tile_rgba_format(pipe, ptRead, 0, 0, readW, readH, + readFormat, buf); + pipe_put_tile_rgba_format(pipe, ptTex, pack.SkipPixels, pack.SkipRows, + readW, readH, drawFormat, buf); + free(buf); + } + else { + /* GL_DEPTH */ + GLuint *buf = (GLuint *) malloc(width * height * sizeof(GLuint)); + pipe_get_tile_z(pipe, ptRead, 0, 0, readW, readH, buf); + pipe_put_tile_z(pipe, ptTex, pack.SkipPixels, pack.SkipRows, + readW, readH, buf); + free(buf); + } + + pipe->transfer_destroy(pipe, ptRead); + pipe->transfer_destroy(pipe, ptTex); + } + + /* OK, the texture 'pt' contains the src image/pixels. Now draw a + * textured quad with that texture. + */ + draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2], + width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, + sv, + num_sampler_view, + driver_vp, + driver_fp, + color, invertTex, GL_FALSE, GL_FALSE); + + pipe_resource_reference(&pt, NULL); + pipe_sampler_view_reference(&sv[0], NULL); +} + + + +void st_init_drawpixels_functions(struct dd_function_table *functions) +{ + functions->DrawPixels = st_DrawPixels; + functions->CopyPixels = st_CopyPixels; +} + + +void +st_destroy_drawpix(struct st_context *st) +{ + GLuint i; + + for (i = 0; i < Elements(st->drawpix.shaders); i++) { + if (st->drawpix.shaders[i]) + _mesa_reference_fragprog(st->ctx, &st->drawpix.shaders[i], NULL); + } + + st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL); + if (st->drawpix.vert_shaders[0]) + ureg_free_tokens(st->drawpix.vert_shaders[0]); + if (st->drawpix.vert_shaders[1]) + ureg_free_tokens(st->drawpix.vert_shaders[1]); +} + +#endif /* FEATURE_drawpix */ -- cgit v1.2.3