static GLboolean _mesa_texstore_z32f_x24s8(TEXSTORE_PARAMS) { GLint img, row; const GLint srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType) / sizeof(uint64_t); assert(dstFormat == MESA_FORMAT_Z32_FLOAT_S8X24_UINT); assert(srcFormat == GL_DEPTH_STENCIL || srcFormat == GL_DEPTH_COMPONENT || srcFormat == GL_STENCIL_INDEX); assert(srcFormat != GL_DEPTH_STENCIL || srcType == GL_UNSIGNED_INT_24_8 || srcType == GL_FLOAT_32_UNSIGNED_INT_24_8_REV); /* In case we only upload depth we need to preserve the stencil */ for (img = 0; img < srcDepth; img++) { uint64_t *dstRow = (uint64_t *) dstSlices[img]; const uint64_t *src = (const uint64_t *) _mesa_image_address(dims, srcPacking, srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, 0, 0); for (row = 0; row < srcHeight; row++) { /* The unpack functions with: * dstType = GL_FLOAT_32_UNSIGNED_INT_24_8_REV * only write their own dword, so the other dword (stencil * or depth) is preserved. */ if (srcFormat != GL_STENCIL_INDEX) _mesa_unpack_depth_span(ctx, srcWidth, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, /* dst type */ dstRow, /* dst addr */ ~0U, srcType, src, srcPacking); if (srcFormat != GL_DEPTH_COMPONENT) _mesa_unpack_stencil_span(ctx, srcWidth, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, /* dst type */ dstRow, /* dst addr */ srcType, src, srcPacking, ctx->_ImageTransferState); src += srcRowStride; dstRow += dstRowStride / sizeof(uint64_t); } } return GL_TRUE; }
/** * glGetTexImage for YCbCr pixels. */ static void get_tex_ycbcr(struct gl_context *ctx, GLuint dimensions, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage) { const GLint width = texImage->Width; const GLint height = texImage->Height; const GLint depth = texImage->Depth; GLint img, row; for (img = 0; img < depth; img++) { GLubyte *srcMap; GLint rowstride; /* map src texture buffer */ ctx->Driver.MapTextureImage(ctx, texImage, img, 0, 0, width, height, GL_MAP_READ_BIT, &srcMap, &rowstride); if (srcMap) { for (row = 0; row < height; row++) { const GLubyte *src = srcMap + row * rowstride; void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, img, row, 0); memcpy(dest, src, width * sizeof(GLushort)); /* check for byte swapping */ if ((texImage->TexFormat == MESA_FORMAT_YCBCR && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) || (texImage->TexFormat == MESA_FORMAT_YCBCR_REV && type == GL_UNSIGNED_SHORT_8_8_MESA)) { if (!ctx->Pack.SwapBytes) _mesa_swap2((GLushort *) dest, width); } else if (ctx->Pack.SwapBytes) { _mesa_swap2((GLushort *) dest, width); } } ctx->Driver.UnmapTextureImage(ctx, texImage, img); } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); break; } } }
void _mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type, GLvoid *image) { const struct gl_convolution_attrib *filter; GLuint row; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (ctx->NewState) { _mesa_update_state(ctx); } if (!_mesa_is_legal_format_and_type(format, type)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)"); return; } if (format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX || format == GL_DEPTH_COMPONENT || format == GL_INTENSITY || type == GL_BITMAP) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)"); return; } switch (target) { case GL_CONVOLUTION_1D: filter = &(ctx->Convolution1D); break; case GL_CONVOLUTION_2D: filter = &(ctx->Convolution2D); break; default: _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)"); return; } for (row = 0; row < filter->Height; row++) { GLvoid *dst = _mesa_image_address( &ctx->Pack, image, filter->Width, filter->Height, format, type, 0, row, 0); const GLfloat *src = filter->Filter + row * filter->Width * 4; _mesa_pack_float_rgba_span(ctx, filter->Width, (const GLfloat (*)[4]) src, format, type, dst, &ctx->Pack, 0); } }
/** * glGetTexImage for depth/stencil pixels. */ static void get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage) { const GLint width = texImage->Width; const GLint height = texImage->Height; const GLint depth = texImage->Depth; GLint img, row; assert(format == GL_DEPTH_STENCIL); assert(type == GL_UNSIGNED_INT_24_8); /* XXX type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV is not handled yet */ for (img = 0; img < depth; img++) { GLubyte *srcMap; GLint rowstride; /* map src texture buffer */ ctx->Driver.MapTextureImage(ctx, texImage, img, 0, 0, width, height, GL_MAP_READ_BIT, &srcMap, &rowstride); if (srcMap) { for (row = 0; row < height; row++) { const GLubyte *src = srcMap + row * rowstride; void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, img, row, 0); /* Unpack from texture's format to GL's z24_s8 layout */ _mesa_unpack_uint_24_8_depth_stencil_row(texImage->TexFormat, width, (const GLuint *) src, dest); if (ctx->Pack.SwapBytes) { _mesa_swap4((GLuint *) dest, width); } } ctx->Driver.UnmapTextureImage(ctx, texImage, img); } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); break; } } }
/** * glGetTexImagefor sRGB pixels; */ static void get_tex_srgb(GLcontext *ctx, GLuint dimensions, GLenum format, GLenum type, GLvoid *pixels, const struct gl_texture_image *texImage) { const GLint width = texImage->Width; const GLint height = texImage->Height; const GLint depth = texImage->Depth; const GLbitfield transferOps = 0x0; GLint img, row; for (img = 0; img < depth; img++) { for (row = 0; row < height; row++) { void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, img, row, 0); GLfloat rgba[MAX_WIDTH][4]; GLint col; /* convert row to RGBA format */ for (col = 0; col < width; col++) { texImage->FetchTexelf(texImage, col, row, img, rgba[col]); if (texImage->_BaseFormat == GL_LUMINANCE) { rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); rgba[col][GCOMP] = 0.0; rgba[col][BCOMP] = 0.0; } else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); rgba[col][GCOMP] = 0.0; rgba[col][BCOMP] = 0.0; } else if (texImage->_BaseFormat == GL_RGB || texImage->_BaseFormat == GL_RGBA) { rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); rgba[col][GCOMP] = linear_to_nonlinear(rgba[col][GCOMP]); rgba[col][BCOMP] = linear_to_nonlinear(rgba[col][BCOMP]); } } _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dest, &ctx->Pack, transferOps); } } }
/** * Store simple 8-bit/value stencil texture data. */ static GLboolean _mesa_texstore_s8(TEXSTORE_PARAMS) { assert(dstFormat == MESA_FORMAT_S_UINT8); assert(srcFormat == GL_STENCIL_INDEX); { const GLint srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType); GLint img, row; GLubyte *stencil = malloc(srcWidth * sizeof(GLubyte)); if (!stencil) return GL_FALSE; for (img = 0; img < srcDepth; img++) { GLubyte *dstRow = dstSlices[img]; const GLubyte *src = (const GLubyte *) _mesa_image_address(dims, srcPacking, srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, 0, 0); for (row = 0; row < srcHeight; row++) { GLint i; /* get the 8-bit stencil values */ _mesa_unpack_stencil_span(ctx, srcWidth, GL_UNSIGNED_BYTE, /* dst type */ stencil, /* dst addr */ srcType, src, srcPacking, ctx->_ImageTransferState); /* merge stencil values into depth values */ for (i = 0; i < srcWidth; i++) dstRow[i] = stencil[i]; src += srcRowStride; dstRow += dstRowStride / sizeof(GLubyte); } } free(stencil); } return GL_TRUE; }
/** * Teximage storage routine for when a simple memcpy will do. * No pixel transfer operations or special texel encodings allowed. * 1D, 2D and 3D images supported. */ static void memcpy_texture(struct gl_context *ctx, GLuint dimensions, mesa_format dstFormat, GLint dstRowStride, GLubyte **dstSlices, GLint srcWidth, GLint srcHeight, GLint srcDepth, GLenum srcFormat, GLenum srcType, const GLvoid *srcAddr, const struct gl_pixelstore_attrib *srcPacking) { const GLint srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType); const GLint srcImageStride = _mesa_image_image_stride(srcPacking, srcWidth, srcHeight, srcFormat, srcType); const GLubyte *srcImage = (const GLubyte *) _mesa_image_address(dimensions, srcPacking, srcAddr, srcWidth, srcHeight, srcFormat, srcType, 0, 0, 0); const GLuint texelBytes = _mesa_get_format_bytes(dstFormat); const GLint bytesPerRow = srcWidth * texelBytes; if (dstRowStride == srcRowStride && dstRowStride == bytesPerRow) { /* memcpy image by image */ GLint img; for (img = 0; img < srcDepth; img++) { GLubyte *dstImage = dstSlices[img]; memcpy(dstImage, srcImage, bytesPerRow * srcHeight); srcImage += srcImageStride; } } else { /* memcpy row by row */ GLint img, row; for (img = 0; img < srcDepth; img++) { const GLubyte *srcRow = srcImage; GLubyte *dstRow = dstSlices[img]; for (row = 0; row < srcHeight; row++) { memcpy(dstRow, srcRow, bytesPerRow); dstRow += dstRowStride; srcRow += srcRowStride; } srcImage += srcImageStride; } } }
/** * glGetTexImage for depth/Z pixels. */ static void get_tex_depth(struct gl_context *ctx, GLuint dimensions, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage) { const GLint width = texImage->Width; const GLint height = texImage->Height; const GLint depth = texImage->Depth; GLint img, row; GLfloat *depthRow = (GLfloat *) malloc(width * sizeof(GLfloat)); if (!depthRow) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); return; } for (img = 0; img < depth; img++) { GLubyte *srcMap; GLint srcRowStride; /* map src texture buffer */ ctx->Driver.MapTextureImage(ctx, texImage, img, 0, 0, width, height, GL_MAP_READ_BIT, &srcMap, &srcRowStride); if (srcMap) { for (row = 0; row < height; row++) { void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, img, row, 0); const GLubyte *src = srcMap + row * srcRowStride; _mesa_unpack_float_z_row(texImage->TexFormat, width, src, depthRow); _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack); } ctx->Driver.UnmapTextureImage(ctx, texImage, img); } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); break; } } free(depthRow); }
/** * glGetTexImage for color index pixels. */ static void get_tex_color_index(GLcontext *ctx, GLuint dimensions, GLenum format, GLenum type, GLvoid *pixels, const struct gl_texture_image *texImage) { const GLint width = texImage->Width; const GLint height = texImage->Height; const GLint depth = texImage->Depth; const GLuint indexBits = _mesa_get_format_bits(texImage->TexFormat, GL_TEXTURE_INDEX_SIZE_EXT); const GLbitfield transferOps = 0x0; GLint img, row, col; for (img = 0; img < depth; img++) { for (row = 0; row < height; row++) { GLuint indexRow[MAX_WIDTH] = { 0 }; void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, img, row, 0); assert(dest); if (indexBits == 8) { const GLubyte *src = (const GLubyte *) texImage->Data; src += width * (img * texImage->Height + row); for (col = 0; col < width; col++) { indexRow[col] = src[col]; } } else if (indexBits == 16) { const GLushort *src = (const GLushort *) texImage->Data; src += width * (img * texImage->Height + row); for (col = 0; col < width; col++) { indexRow[col] = src[col]; } } else { _mesa_problem(ctx, "Color index problem in _mesa_GetTexImage"); } _mesa_pack_index_span(ctx, width, type, dest, indexRow, &ctx->Pack, transferOps); } } }
/** * glGetTexImage for stencil pixels. */ static void get_tex_stencil(struct gl_context *ctx, GLuint dimensions, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage) { const GLint width = texImage->Width; const GLint height = texImage->Height; const GLint depth = texImage->Depth; GLint img, row; assert(format == GL_STENCIL_INDEX); for (img = 0; img < depth; img++) { GLubyte *srcMap; GLint rowstride; /* map src texture buffer */ ctx->Driver.MapTextureImage(ctx, texImage, img, 0, 0, width, height, GL_MAP_READ_BIT, &srcMap, &rowstride); if (srcMap) { for (row = 0; row < height; row++) { const GLubyte *src = srcMap + row * rowstride; void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, img, row, 0); // _mesa_unpack_ubyte_stencil_row(texImage->TexFormat, // width, // (const GLuint *) src, // dest); } ctx->Driver.UnmapTextureImage(ctx, texImage, img); } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); break; } } }
/** * glGetTexImage for depth/stencil pixels. */ static void get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage) { const GLint width = texImage->Width; const GLint height = texImage->Height; const GLint depth = texImage->Depth; GLint img, row; for (img = 0; img < depth; img++) { GLubyte *srcMap; GLint rowstride; /* map src texture buffer */ ctx->Driver.MapTextureImage(ctx, texImage, img, 0, 0, width, height, GL_MAP_READ_BIT, &srcMap, &rowstride); if (srcMap) { for (row = 0; row < height; row++) { const GLubyte *src = srcMap + row * rowstride; void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, img, row, 0); /* XXX Z24_S8 vs. S8_Z24??? */ memcpy(dest, src, width * sizeof(GLuint)); if (ctx->Pack.SwapBytes) { _mesa_swap4((GLuint *) dest, width); } } ctx->Driver.UnmapTextureImage(ctx, texImage, img); } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); break; } } }
/** * Get a color texture image with decompression. */ static void get_tex_rgba_compressed(struct gl_context *ctx, GLuint dimensions, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage, GLbitfield transferOps) { /* don't want to apply sRGB -> RGB conversion here so override the format */ const mesa_format texFormat = _mesa_get_srgb_format_linear(texImage->TexFormat); const GLenum baseFormat = _mesa_get_format_base_format(texFormat); const GLuint width = texImage->Width; const GLuint height = texImage->Height; const GLuint depth = texImage->Depth; GLfloat *tempImage, *tempSlice; GLuint slice; int srcStride, dstStride; uint32_t dstFormat; bool needsRebase; uint8_t rebaseSwizzle[4]; /* Decompress into temp float buffer, then pack into user buffer */ tempImage = malloc(width * height * depth * 4 * sizeof(GLfloat)); if (!tempImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); return; } /* Decompress the texture image slices - results in 'tempImage' */ for (slice = 0; slice < depth; slice++) { GLubyte *srcMap; GLint srcRowStride; tempSlice = tempImage + slice * 4 * width * height; ctx->Driver.MapTextureImage(ctx, texImage, slice, 0, 0, width, height, GL_MAP_READ_BIT, &srcMap, &srcRowStride); if (srcMap) { _mesa_decompress_image(texFormat, width, height, srcMap, srcRowStride, tempSlice); ctx->Driver.UnmapTextureImage(ctx, texImage, slice); } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); free(tempImage); return; } } /* Depending on the base format involved we may need to apply a rebase * transform (for example: if we download to a Luminance format we want * G=0 and B=0). */ if (baseFormat == GL_LUMINANCE || baseFormat == GL_INTENSITY) { needsRebase = true; rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X; rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_ONE; } else if (baseFormat == GL_LUMINANCE_ALPHA) { needsRebase = true; rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X; rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_W; } else { needsRebase = false; } srcStride = 4 * width * sizeof(GLfloat); dstStride = _mesa_image_row_stride(&ctx->Pack, width, format, type); dstFormat = _mesa_format_from_format_and_type(format, type); tempSlice = tempImage; for (slice = 0; slice < depth; slice++) { void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, slice, 0, 0); // _mesa_format_convert(dest, dstFormat, dstStride, // tempSlice, RGBA32_FLOAT, srcStride, // width, height, // needsRebase ? rebaseSwizzle : NULL); tempSlice += 4 * width * height; } free(tempImage); }
/** * Get an uncompressed color texture image. */ static void get_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage, GLbitfield transferOps) { /* don't want to apply sRGB -> RGB conversion here so override the format */ const gl_format texFormat = _mesa_get_srgb_format_linear(texImage->TexFormat); const GLuint width = texImage->Width; const GLenum destBaseFormat = _mesa_base_tex_format(ctx, format); GLenum rebaseFormat = GL_NONE; GLuint height = texImage->Height; GLuint depth = texImage->Depth; GLuint img, row; GLfloat (*rgba)[4]; GLuint (*rgba_uint)[4]; GLboolean tex_is_integer = _mesa_is_format_integer_color(texImage->TexFormat); GLboolean tex_is_uint = _mesa_is_format_unsigned(texImage->TexFormat); /* Allocate buffer for one row of texels */ rgba = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat)); rgba_uint = (GLuint (*)[4]) rgba; if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); return; } if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) { depth = height; height = 1; } if (texImage->_BaseFormat == GL_LUMINANCE || texImage->_BaseFormat == GL_INTENSITY || texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { /* If a luminance (or intensity) texture is read back as RGB(A), the * returned value should be (L,0,0,1), not (L,L,L,1). Set rebaseFormat * here to get G=B=0. */ rebaseFormat = texImage->_BaseFormat; } else if ((texImage->_BaseFormat == GL_RGBA || texImage->_BaseFormat == GL_RGB || texImage->_BaseFormat == GL_RG) && (destBaseFormat == GL_LUMINANCE || destBaseFormat == GL_LUMINANCE_ALPHA || destBaseFormat == GL_LUMINANCE_INTEGER_EXT || destBaseFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT)) { /* If we're reading back an RGB(A) texture as luminance then we need * to return L=tex(R). Note, that's different from glReadPixels which * returns L=R+G+B. */ rebaseFormat = GL_LUMINANCE_ALPHA; /* this covers GL_LUMINANCE too */ } for (img = 0; img < depth; img++) { GLubyte *srcMap; GLint rowstride; /* map src texture buffer */ ctx->Driver.MapTextureImage(ctx, texImage, img, 0, 0, width, height, GL_MAP_READ_BIT, &srcMap, &rowstride); if (srcMap) { for (row = 0; row < height; row++) { const GLubyte *src = srcMap + row * rowstride; void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, img, row, 0); if (tex_is_integer) { _mesa_unpack_uint_rgba_row(texFormat, width, src, rgba_uint); if (rebaseFormat) _mesa_rebase_rgba_uint(width, rgba_uint, rebaseFormat); if (tex_is_uint) { _mesa_pack_rgba_span_from_uints(ctx, width, (GLuint (*)[4]) rgba_uint, format, type, dest); } else { _mesa_pack_rgba_span_from_ints(ctx, width, (GLint (*)[4]) rgba_uint, format, type, dest); } } else { _mesa_unpack_rgba_row(texFormat, width, src, rgba); if (rebaseFormat) _mesa_rebase_rgba_float(width, rgba, rebaseFormat); _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dest, &ctx->Pack, transferOps); } } /* Unmap the src texture buffer */ ctx->Driver.UnmapTextureImage(ctx, texImage, img); } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); break; } } free(rgba); }
/** * Get a color texture image with decompression. */ static void get_tex_rgba_compressed(struct gl_context *ctx, GLuint dimensions, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage, GLbitfield transferOps) { /* don't want to apply sRGB -> RGB conversion here so override the format */ const gl_format texFormat = _mesa_get_srgb_format_linear(texImage->TexFormat); const GLenum baseFormat = _mesa_get_format_base_format(texFormat); const GLenum destBaseFormat = _mesa_base_tex_format(ctx, format); GLenum rebaseFormat = GL_NONE; const GLuint width = texImage->Width; const GLuint height = texImage->Height; const GLuint depth = texImage->Depth; GLfloat *tempImage, *srcRow; GLuint row; /* Decompress into temp float buffer, then pack into user buffer */ tempImage = (GLfloat *) malloc(width * height * depth * 4 * sizeof(GLfloat)); if (!tempImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); return; } /* Decompress the texture image - results in 'tempImage' */ { GLubyte *srcMap; GLint srcRowStride; ctx->Driver.MapTextureImage(ctx, texImage, 0, 0, 0, width, height, GL_MAP_READ_BIT, &srcMap, &srcRowStride); if (srcMap) { _mesa_decompress_image(texFormat, width, height, srcMap, srcRowStride, tempImage); ctx->Driver.UnmapTextureImage(ctx, texImage, 0); } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); free(tempImage); return; } } if (baseFormat == GL_LUMINANCE || baseFormat == GL_INTENSITY || baseFormat == GL_LUMINANCE_ALPHA) { /* If a luminance (or intensity) texture is read back as RGB(A), the * returned value should be (L,0,0,1), not (L,L,L,1). Set rebaseFormat * here to get G=B=0. */ rebaseFormat = texImage->_BaseFormat; } else if ((baseFormat == GL_RGBA || baseFormat == GL_RGB || baseFormat == GL_RG) && (destBaseFormat == GL_LUMINANCE || destBaseFormat == GL_LUMINANCE_ALPHA || destBaseFormat == GL_LUMINANCE_INTEGER_EXT || destBaseFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT)) { /* If we're reading back an RGB(A) texture as luminance then we need * to return L=tex(R). Note, that's different from glReadPixels which * returns L=R+G+B. */ rebaseFormat = GL_LUMINANCE_ALPHA; /* this covers GL_LUMINANCE too */ } if (rebaseFormat) { _mesa_rebase_rgba_float(width * height, (GLfloat (*)[4]) tempImage, rebaseFormat); } srcRow = tempImage; for (row = 0; row < height; row++) { void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, 0, row, 0); _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) srcRow, format, type, dest, &ctx->Pack, transferOps); srcRow += width * 4; } free(tempImage); }
static GLboolean texstore_rgba(TEXSTORE_PARAMS) { void *tempImage = NULL, *tempRGBA = NULL; int srcRowStride, img; GLubyte *src, *dst; uint32_t srcMesaFormat; uint8_t rebaseSwizzle[4]; bool needRebase; bool transferOpsDone = false; /* We have to handle MESA_FORMAT_YCBCR manually because it is a special case * and _mesa_format_convert does not support it. In this case the we only * allow conversions between YCBCR formats and it is mostly a memcpy. */ if (dstFormat == MESA_FORMAT_YCBCR || dstFormat == MESA_FORMAT_YCBCR_REV) { return _mesa_texstore_ycbcr(ctx, dims, baseInternalFormat, dstFormat, dstRowStride, dstSlices, srcWidth, srcHeight, srcDepth, srcFormat, srcType, srcAddr, srcPacking); } /* We have to deal with GL_COLOR_INDEX manually because * _mesa_format_convert does not handle this format. So what we do here is * convert it to RGBA ubyte first and then convert from that to dst as usual. */ if (srcFormat == GL_COLOR_INDEX) { /* Notice that this will already handle byte swapping if necessary */ tempImage = _mesa_unpack_color_index_to_rgba_ubyte(ctx, dims, srcAddr, srcFormat, srcType, srcWidth, srcHeight, srcDepth, srcPacking, ctx->_ImageTransferState); if (!tempImage) return GL_FALSE; /* _mesa_unpack_color_index_to_rgba_ubyte has handled transferops * if needed. */ transferOpsDone = true; /* Now we only have to adjust our src info for a conversion from * the RGBA ubyte and then we continue as usual. */ srcAddr = tempImage; srcFormat = GL_RGBA; srcType = GL_UNSIGNED_BYTE; } else if (srcPacking->SwapBytes) { /* We have to handle byte-swapping scenarios before calling * _mesa_format_convert */ GLint swapSize = _mesa_sizeof_packed_type(srcType); if (swapSize == 2 || swapSize == 4) { int bytesPerPixel = _mesa_bytes_per_pixel(srcFormat, srcType); int swapsPerPixel = bytesPerPixel / swapSize; int elementCount = srcWidth * srcHeight * srcDepth; assert(bytesPerPixel % swapSize == 0); tempImage = malloc(elementCount * bytesPerPixel); if (!tempImage) return GL_FALSE; if (swapSize == 2) _mesa_swap2_copy(tempImage, (GLushort *) srcAddr, elementCount * swapsPerPixel); else _mesa_swap4_copy(tempImage, (GLuint *) srcAddr, elementCount * swapsPerPixel); srcAddr = tempImage; } } srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType); srcMesaFormat = _mesa_format_from_format_and_type(srcFormat, srcType); dstFormat = _mesa_get_srgb_format_linear(dstFormat); /* If we have transferOps then we need to convert to RGBA float first, then apply transferOps, then do the conversion to dst */ if (!transferOpsDone && _mesa_texstore_needs_transfer_ops(ctx, baseInternalFormat, dstFormat)) { /* Allocate RGBA float image */ int elementCount = srcWidth * srcHeight * srcDepth; tempRGBA = malloc(4 * elementCount * sizeof(float)); if (!tempRGBA) { free(tempImage); free(tempRGBA); return GL_FALSE; } /* Convert from src to RGBA float */ src = (GLubyte *) srcAddr; dst = (GLubyte *) tempRGBA; for (img = 0; img < srcDepth; img++) { _mesa_format_convert(dst, RGBA32_FLOAT, 4 * srcWidth * sizeof(float), src, srcMesaFormat, srcRowStride, srcWidth, srcHeight, NULL); src += srcHeight * srcRowStride; dst += srcHeight * 4 * srcWidth * sizeof(float); } /* Apply transferOps */ _mesa_apply_rgba_transfer_ops(ctx, ctx->_ImageTransferState, elementCount, (float(*)[4]) tempRGBA); /* Now we have to adjust our src info for a conversion from * the RGBA float image and then we continue as usual. */ srcAddr = tempRGBA; srcFormat = GL_RGBA; srcType = GL_FLOAT; srcRowStride = srcWidth * 4 * sizeof(float); srcMesaFormat = RGBA32_FLOAT; } src = (GLubyte *) _mesa_image_address(dims, srcPacking, srcAddr, srcWidth, srcHeight, srcFormat, srcType, 0, 0, 0); if (_mesa_get_format_base_format(dstFormat) != baseInternalFormat) { needRebase = _mesa_compute_rgba2base2rgba_component_mapping(baseInternalFormat, rebaseSwizzle); } else { needRebase = false; } for (img = 0; img < srcDepth; img++) { _mesa_format_convert(dstSlices[img], dstFormat, dstRowStride, src, srcMesaFormat, srcRowStride, srcWidth, srcHeight, needRebase ? rebaseSwizzle : NULL); src += srcHeight * srcRowStride; } free(tempImage); free(tempRGBA); return GL_TRUE; }
/* Pros: * - no waiting for idle before updating framebuffer. * * Cons: * - if upload is by memcpy, this may actually be slower than fallback path. * - uploads the whole image even if destination is clipped * * Need to benchmark. * * Given the questions about performance, implement for pbo's only. * This path is definitely a win if the pbo is already in agp. If it * turns out otherwise, we can add the code necessary to upload client * data to agp space before performing the blit. (Though it may turn * out to be better/simpler just to use the texture engine). */ static GLboolean do_blit_drawpixels(GLcontext * ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid * pixels) { struct intel_context *intel = intel_context(ctx); struct intel_region *dest = intel_drawbuf_region(intel); struct intel_buffer_object *src = intel_buffer_object(unpack->BufferObj); GLuint src_offset; GLuint rowLength; struct _DriFenceObject *fence = NULL; if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s\n", __FUNCTION__); if (!dest) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - no dest\n", __FUNCTION__); return GL_FALSE; } if (src) { /* This validation should be done by core mesa: */ if (!_mesa_validate_pbo_access(2, unpack, width, height, 1, format, type, pixels)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels"); return GL_TRUE; } } else { /* PBO only for now: */ if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - not PBO\n", __FUNCTION__); return GL_FALSE; } if (!intel_check_blit_format(dest, format, type)) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad format for blit\n", __FUNCTION__); return GL_FALSE; } if (!intel_check_blit_fragment_ops(ctx)) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad GL fragment state for blitter\n", __FUNCTION__); return GL_FALSE; } if (ctx->Pixel.ZoomX != 1.0F) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad PixelZoomX for blit\n", __FUNCTION__); return GL_FALSE; } if (unpack->RowLength > 0) rowLength = unpack->RowLength; else rowLength = width; if (ctx->Pixel.ZoomY == -1.0F) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad PixelZoomY for blit\n", __FUNCTION__); return GL_FALSE; /* later */ y -= height; } else if (ctx->Pixel.ZoomY == 1.0F) { rowLength = -rowLength; } else { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad PixelZoomY for blit\n", __FUNCTION__); return GL_FALSE; } src_offset = (GLuint) _mesa_image_address(2, unpack, pixels, width, height, format, type, 0, 0, 0); intelFlush(&intel->ctx); LOCK_HARDWARE(intel); if (intel->driDrawable->numClipRects) { __DRIdrawablePrivate *dPriv = intel->driDrawable; int nbox = dPriv->numClipRects; drm_clip_rect_t *box = dPriv->pClipRects; drm_clip_rect_t rect; drm_clip_rect_t dest_rect; struct _DriBufferObject *src_buffer = intel_bufferobj_buffer(intel, src, INTEL_READ); int i; dest_rect.x1 = dPriv->x + x; dest_rect.y1 = dPriv->y + dPriv->h - (y + height); dest_rect.x2 = dest_rect.x1 + width; dest_rect.y2 = dest_rect.y1 + height; for (i = 0; i < nbox; i++) { if (!intel_intersect_cliprects(&rect, &dest_rect, &box[i])) continue; intelEmitCopyBlit(intel, dest->cpp, rowLength, src_buffer, src_offset, dest->pitch, dest->buffer, 0, rect.x1 - dest_rect.x1, rect.y2 - dest_rect.y2, rect.x1, rect.y1, rect.x2 - rect.x1, rect.y2 - rect.y1, ctx->Color.ColorLogicOpEnabled ? ctx->Color.LogicOp : GL_COPY); } fence = intel_batchbuffer_flush(intel->batch); driFenceReference(fence); } UNLOCK_HARDWARE(intel); if (fence) { driFenceFinish(fence, DRM_FENCE_TYPE_EXE | DRM_I915_FENCE_TYPE_RW, GL_FALSE); driFenceUnReference(fence); } if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - DONE\n", __FUNCTION__); return GL_TRUE; }
/** * glGetTexImagefor RGBA, Luminance, etc. pixels. * This is the slow way since we use texture sampling. */ static void get_tex_rgba(GLcontext *ctx, GLuint dimensions, GLenum format, GLenum type, GLvoid *pixels, const struct gl_texture_image *texImage) { const GLint width = texImage->Width; const GLint height = texImage->Height; const GLint depth = texImage->Depth; /* Normally, no pixel transfer ops are performed during glGetTexImage. * The only possible exception is component clamping to [0,1]. */ GLbitfield transferOps = 0x0; GLint img, row; for (img = 0; img < depth; img++) { for (row = 0; row < height; row++) { void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, img, row, 0); GLfloat rgba[MAX_WIDTH][4]; GLint col; GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat); /* clamp does not apply to GetTexImage (final conversion)? * Looks like we need clamp though when going from format * containing negative values to unsigned format. */ if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) { transferOps |= IMAGE_CLAMP_BIT; } else if (!type_with_negative_values(type) && (dataType == GL_FLOAT || dataType == GL_SIGNED_NORMALIZED)) { transferOps |= IMAGE_CLAMP_BIT; } for (col = 0; col < width; col++) { texImage->FetchTexelf(texImage, col, row, img, rgba[col]); if (texImage->_BaseFormat == GL_ALPHA) { rgba[col][RCOMP] = 0.0F; rgba[col][GCOMP] = 0.0F; rgba[col][BCOMP] = 0.0F; } else if (texImage->_BaseFormat == GL_LUMINANCE) { rgba[col][GCOMP] = 0.0F; rgba[col][BCOMP] = 0.0F; rgba[col][ACOMP] = 1.0F; } else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { rgba[col][GCOMP] = 0.0F; rgba[col][BCOMP] = 0.0F; } else if (texImage->_BaseFormat == GL_INTENSITY) { rgba[col][GCOMP] = 0.0F; rgba[col][BCOMP] = 0.0F; rgba[col][ACOMP] = 1.0F; } } _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dest, &ctx->Pack, transferOps); } } }
/** * This is the software fallback for Driver.GetTexImage(). * All error checking will have been done before this routine is called. */ void _mesa_get_teximage(GLcontext *ctx, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_object *texObj, struct gl_texture_image *texImage) { const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; if (ctx->Pack.BufferObj->Name) { /* Packing texture image into a PBO. * Map the (potentially) VRAM-based buffer into our process space so * we can write into it with the code below. * A hardware driver might use a sophisticated blit to move the * texture data to the PBO if the PBO is in VRAM along with the texture. */ GLubyte *buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj); if (!buf) { /* buffer is already mapped - that's an error */ _mesa_error(ctx, GL_INVALID_OPERATION,"glGetTexImage(PBO is mapped)"); return; } /* <pixels> was an offset into the PBO. * Now make it a real, client-side pointer inside the mapped region. */ pixels = ADD_POINTERS(buf, pixels); } else if (!pixels) { /* not an error */ return; } { const GLint width = texImage->Width; const GLint height = texImage->Height; const GLint depth = texImage->Depth; GLint img, row; for (img = 0; img < depth; img++) { for (row = 0; row < height; row++) { /* compute destination address in client memory */ GLvoid *dest = _mesa_image_address( dimensions, &ctx->Pack, pixels, width, height, format, type, img, row, 0); assert(dest); if (format == GL_COLOR_INDEX) { GLuint indexRow[MAX_WIDTH]; GLint col; /* Can't use FetchTexel here because that returns RGBA */ if (texImage->TexFormat->IndexBits == 8) { const GLubyte *src = (const GLubyte *) texImage->Data; src += width * (img * texImage->Height + row); for (col = 0; col < width; col++) { indexRow[col] = src[col]; } } else if (texImage->TexFormat->IndexBits == 16) { const GLushort *src = (const GLushort *) texImage->Data; src += width * (img * texImage->Height + row); for (col = 0; col < width; col++) { indexRow[col] = src[col]; } } else { _mesa_problem(ctx, "Color index problem in _mesa_GetTexImage"); } _mesa_pack_index_span(ctx, width, type, dest, indexRow, &ctx->Pack, 0 /* no image transfer */); } else if (format == GL_DEPTH_COMPONENT) { GLfloat depthRow[MAX_WIDTH]; GLint col; for (col = 0; col < width; col++) { (*texImage->FetchTexelf)(texImage, col, row, img, depthRow + col); } _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack); } else if (format == GL_DEPTH_STENCIL_EXT) { /* XXX Note: we're bypassing texImage->FetchTexel()! */ const GLuint *src = (const GLuint *) texImage->Data; src += width * row + width * height * img; _mesa_memcpy(dest, src, width * sizeof(GLuint)); if (ctx->Pack.SwapBytes) { _mesa_swap4((GLuint *) dest, width); } } else if (format == GL_YCBCR_MESA) { /* No pixel transfer */ const GLint rowstride = texImage->RowStride; MEMCPY(dest, (const GLushort *) texImage->Data + row * rowstride, width * sizeof(GLushort)); /* check for byte swapping */ if ((texImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) || (texImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR_REV && type == GL_UNSIGNED_SHORT_8_8_MESA)) { if (!ctx->Pack.SwapBytes) _mesa_swap2((GLushort *) dest, width); } else if (ctx->Pack.SwapBytes) { _mesa_swap2((GLushort *) dest, width); } } #if FEATURE_EXT_texture_sRGB else if (is_srgb_teximage(texImage)) { /* special case this since need to backconvert values */ /* convert row to RGBA format */ GLfloat rgba[MAX_WIDTH][4]; GLint col; GLbitfield transferOps = 0x0; for (col = 0; col < width; col++) { (*texImage->FetchTexelf)(texImage, col, row, img, rgba[col]); if (texImage->_BaseFormat == GL_LUMINANCE) { rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); rgba[col][GCOMP] = 0.0; rgba[col][BCOMP] = 0.0; } else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); rgba[col][GCOMP] = 0.0; rgba[col][BCOMP] = 0.0; } else if (texImage->_BaseFormat == GL_RGB || texImage->_BaseFormat == GL_RGBA) { rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); rgba[col][GCOMP] = linear_to_nonlinear(rgba[col][GCOMP]); rgba[col][BCOMP] = linear_to_nonlinear(rgba[col][BCOMP]); } } _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dest, &ctx->Pack, transferOps); } #endif /* FEATURE_EXT_texture_sRGB */ else { /* general case: convert row to RGBA format */ GLfloat rgba[MAX_WIDTH][4]; GLint col; GLbitfield transferOps = 0x0; /* clamp does not apply to GetTexImage (final conversion)? * Looks like we need clamp though when going from format * containing negative values to unsigned format. */ if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) transferOps |= IMAGE_CLAMP_BIT; else if (!type_with_negative_values(type) && (texImage->TexFormat->DataType == GL_FLOAT || texImage->TexFormat->DataType == GL_SIGNED_NORMALIZED)) transferOps |= IMAGE_CLAMP_BIT; for (col = 0; col < width; col++) { (*texImage->FetchTexelf)(texImage, col, row, img, rgba[col]); if (texImage->_BaseFormat == GL_ALPHA) { rgba[col][RCOMP] = 0.0; rgba[col][GCOMP] = 0.0; rgba[col][BCOMP] = 0.0; } else if (texImage->_BaseFormat == GL_LUMINANCE) { rgba[col][GCOMP] = 0.0; rgba[col][BCOMP] = 0.0; rgba[col][ACOMP] = 1.0; } else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { rgba[col][GCOMP] = 0.0; rgba[col][BCOMP] = 0.0; } else if (texImage->_BaseFormat == GL_INTENSITY) { rgba[col][GCOMP] = 0.0; rgba[col][BCOMP] = 0.0; rgba[col][ACOMP] = 1.0; } } _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dest, &ctx->Pack, transferOps); } /* format */ } /* row */ } /* img */ } if (ctx->Pack.BufferObj->Name) { ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, ctx->Pack.BufferObj); } }
/** * Get an uncompressed color texture image. */ static void get_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage, GLbitfield transferOps) { /* don't want to apply sRGB -> RGB conversion here so override the format */ const mesa_format texFormat = _mesa_get_srgb_format_linear(texImage->TexFormat); const GLuint width = texImage->Width; GLuint height = texImage->Height; GLuint depth = texImage->Depth; GLuint img; GLboolean dst_is_integer; uint32_t dst_format; int dst_stride; uint8_t rebaseSwizzle[4]; bool needsRebase; void *rgba = NULL; if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) { depth = height; height = 1; } /* Depending on the base format involved we may need to apply a rebase * transform (for example: if we download to a Luminance format we want * G=0 and B=0). */ if (texImage->_BaseFormat == GL_LUMINANCE || texImage->_BaseFormat == GL_INTENSITY) { needsRebase = true; rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X; rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_ONE; } else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { needsRebase = true; rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X; rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_W; // } else if (texImage->_BaseFormat != _mesa_get_format_base_format(texFormat)) { // needsRebase = // _mesa_compute_rgba2base2rgba_component_mapping(texImage->_BaseFormat, // rebaseSwizzle); } else { needsRebase = false; } /* Describe the dst format */ dst_is_integer = _mesa_is_enum_format_integer(format); dst_format = _mesa_format_from_format_and_type(format, type); dst_stride = _mesa_image_row_stride(&ctx->Pack, width, format, type); /* Since _mesa_format_convert does not handle transferOps we need to handle * them before we call the function. This requires to convert to RGBA float * first so we can call _mesa_apply_rgba_transfer_ops. If the dst format is * integer then transferOps do not apply. */ assert(!transferOps || (transferOps && !dst_is_integer)); (void) dst_is_integer; /* silence unused var warning */ for (img = 0; img < depth; img++) { GLubyte *srcMap; GLint rowstride; GLubyte *img_src; void *dest; void *src; int src_stride; uint32_t src_format; /* map src texture buffer */ ctx->Driver.MapTextureImage(ctx, texImage, img, 0, 0, width, height, GL_MAP_READ_BIT, &srcMap, &rowstride); if (!srcMap) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); goto done; } img_src = srcMap; dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, img, 0, 0); if (transferOps) { uint32_t rgba_format; int rgba_stride; bool need_convert = false; /* We will convert to RGBA float */ // rgba_format = RGBA32_FLOAT; rgba_stride = width * 4 * sizeof(GLfloat); /* If we are lucky and the dst format matches the RGBA format we need * to convert to, then we can convert directly into the dst buffer * and avoid the final conversion/copy from the rgba buffer to the dst * buffer. */ if (format == rgba_format) { rgba = dest; } else if (rgba == NULL) { /* Allocate the RGBA buffer only once */ need_convert = true; rgba = malloc(height * rgba_stride); if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); ctx->Driver.UnmapTextureImage(ctx, texImage, img); return; } } // _mesa_format_convert(rgba, rgba_format, rgba_stride, // img_src, texFormat, rowstride, // width, height, // needsRebase ? rebaseSwizzle : NULL); /* Handle transfer ops now */ _mesa_apply_rgba_transfer_ops(ctx, transferOps, width * height, rgba); /* If we had to rebase, we have already handled that */ needsRebase = false; /* If we were lucky and our RGBA conversion matches the dst format, then * we are done. */ if (!need_convert) goto do_swap; /* Otherwise, we need to convert from RGBA to dst next */ src = rgba; src_format = rgba_format; src_stride = rgba_stride; } else { /* No RGBA conversion needed, convert directly to dst */ src = img_src; src_format = texFormat; src_stride = rowstride; } /* Do the conversion to destination format */ // _mesa_format_convert(dest, dst_format, dst_stride, // src, src_format, src_stride, // width, height, // needsRebase ? rebaseSwizzle : NULL); do_swap: /* Handle byte swapping if required */ if (ctx->Pack.SwapBytes) { GLint swapSize = _mesa_sizeof_packed_type(type); if (swapSize == 2 || swapSize == 4) { int swapsPerPixel = _mesa_bytes_per_pixel(format, type) / swapSize; assert(_mesa_bytes_per_pixel(format, type) % swapSize == 0); if (swapSize == 2) _mesa_swap2((GLushort *) dest, width * height * swapsPerPixel); else if (swapSize == 4) _mesa_swap4((GLuint *) dest, width * height * swapsPerPixel); } } /* Unmap the src texture buffer */ ctx->Driver.UnmapTextureImage(ctx, texImage, img); } done: if (rgba) free(rgba); }
static GLboolean do_texture_drawpixels(GLcontext * ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid * pixels) { struct intel_context *intel = intel_context(ctx); struct intel_region *dst = intel_drawbuf_region(intel); struct intel_buffer_object *src = intel_buffer_object(unpack->BufferObj); GLuint rowLength = unpack->RowLength ? unpack->RowLength : width; GLuint src_offset; if (INTEL_DEBUG & DEBUG_PIXEL) fprintf(stderr, "%s\n", __FUNCTION__); intelFlush(&intel->ctx); intel->vtbl.render_start(intel); intel->vtbl.emit_state(intel); if (!dst) return GL_FALSE; if (src) { if (!_mesa_validate_pbo_access(2, unpack, width, height, 1, format, type, pixels)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels"); return GL_TRUE; } } else { /* PBO only for now: */ /* _mesa_printf("%s - not PBO\n", __FUNCTION__); */ return GL_FALSE; } /* There are a couple of things we can't do yet, one of which is * set the correct state for pixel operations when GL texturing is * enabled. That's a pretty rare state and probably not worth the * effort. A completely device-independent version of this may do * more. * * Similarly, we make no attempt to merge metaops processing with * an enabled fragment program, though it would certainly be * possible. */ if (!intel_check_meta_tex_fragment_ops(ctx)) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad GL fragment state for metaops texture\n", __FUNCTION__); return GL_FALSE; } intel->vtbl.install_meta_state(intel); /* Is this true? Also will need to turn depth testing on according * to state: */ intel->vtbl.meta_no_stencil_write(intel); intel->vtbl.meta_no_depth_write(intel); /* Set the 3d engine to draw into the destination region: */ intel->vtbl.meta_draw_region(intel, dst, intel->intelScreen->depth_region); intel->vtbl.meta_import_pixel_state(intel); src_offset = (GLuint) _mesa_image_address(2, unpack, pixels, width, height, format, type, 0, 0, 0); /* Setup the pbo up as a rectangular texture, if possible. * * TODO: This is almost always possible if the i915 fragment * program is adjusted to correctly swizzle the sampled colors. * The major exception is any 24bit texture, like RGB888, for which * there is no hardware support. */ if (!intel->vtbl.meta_tex_rect_source(intel, src->buffer, src_offset, rowLength, height, format, type)) { intel->vtbl.leave_meta_state(intel); return GL_FALSE; } intel->vtbl.meta_texture_blend_replace(intel); LOCK_HARDWARE(intel); if (intel->driDrawable->numClipRects) { __DRIdrawablePrivate *dPriv = intel->driDrawable; GLint srcx, srcy; GLint dstx, dsty; dstx = x; dsty = dPriv->h - (y + height); srcx = 0; /* skiprows/pixels already done */ srcy = 0; if (0) { const GLint orig_x = dstx; const GLint orig_y = dsty; if (!_mesa_clip_to_region(0, 0, dst->pitch, dst->height, &dstx, &dsty, &width, &height)) goto out; srcx += dstx - orig_x; srcy += dsty - orig_y; } if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("draw %d,%d %dx%d\n", dstx, dsty, width, height); /* Must use the regular cliprect mechanism in order to get the * drawing origin set correctly. Otherwise scissor state is in * incorrect coordinate space. Does this even need to hold the * lock??? */ intel_meta_draw_quad(intel, dstx, dstx + width * ctx->Pixel.ZoomX, dPriv->h - (y + height * ctx->Pixel.ZoomY), dPriv->h - (y), -ctx->Current.RasterPos[2] * .5, 0x00ff00ff, srcx, srcx + width, srcy + height, srcy); out: intel->vtbl.leave_meta_state(intel); intel_batchbuffer_flush(intel->batch); } UNLOCK_HARDWARE(intel); return GL_TRUE; }
static GLboolean do_blit_readpixels(GLcontext * ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *pack, GLvoid * pixels) { struct intel_context *intel = intel_context(ctx); struct intel_region *src = intel_readbuf_region(intel); struct intel_buffer_object *dst = intel_buffer_object(pack->BufferObj); GLuint dst_offset; GLuint rowLength; drm_intel_bo *dst_buffer; GLboolean all; GLint dst_x, dst_y; if (INTEL_DEBUG & DEBUG_PIXEL) printf("%s\n", __FUNCTION__); if (!src) return GL_FALSE; if (!_mesa_is_bufferobj(pack->BufferObj)) { /* PBO only for now: */ if (INTEL_DEBUG & DEBUG_PIXEL) printf("%s - not PBO\n", __FUNCTION__); return GL_FALSE; } if (ctx->_ImageTransferState || !intel_check_blit_format(src, format, type)) { if (INTEL_DEBUG & DEBUG_PIXEL) printf("%s - bad format for blit\n", __FUNCTION__); return GL_FALSE; } if (pack->Alignment != 1 || pack->SwapBytes || pack->LsbFirst) { if (INTEL_DEBUG & DEBUG_PIXEL) printf("%s: bad packing params\n", __FUNCTION__); return GL_FALSE; } if (pack->RowLength > 0) rowLength = pack->RowLength; else rowLength = width; if (pack->Invert) { if (INTEL_DEBUG & DEBUG_PIXEL) printf("%s: MESA_PACK_INVERT not done yet\n", __FUNCTION__); return GL_FALSE; } else { if (ctx->ReadBuffer->Name == 0) rowLength = -rowLength; } dst_offset = (GLintptr) _mesa_image_address(2, pack, pixels, width, height, format, type, 0, 0, 0); if (!_mesa_clip_copytexsubimage(ctx, &dst_x, &dst_y, &x, &y, &width, &height)) { return GL_TRUE; } intel_prepare_render(intel); all = (width * height * src->cpp == dst->Base.Size && x == 0 && dst_offset == 0); dst_x = 0; dst_y = 0; dst_buffer = intel_bufferobj_buffer(intel, dst, all ? INTEL_WRITE_FULL : INTEL_WRITE_PART); if (ctx->ReadBuffer->Name == 0) y = ctx->ReadBuffer->Height - (y + height); if (!intelEmitCopyBlit(intel, src->cpp, src->pitch, src->buffer, 0, src->tiling, rowLength, dst_buffer, dst_offset, GL_FALSE, x, y, dst_x, dst_y, width, height, GL_COPY)) { return GL_FALSE; } if (INTEL_DEBUG & DEBUG_PIXEL) printf("%s - DONE\n", __FUNCTION__); return GL_TRUE; }
void _mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image) { GLint baseFormat; GLint i, components; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); if (target != GL_CONVOLUTION_2D) { _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)"); return; } baseFormat = base_filter_format(internalFormat); if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) { _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)"); return; } if (width < 0 || width > MAX_CONVOLUTION_WIDTH) { _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)"); return; } if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) { _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)"); return; } if (!_mesa_is_legal_format_and_type(format, type)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter2D(format or type)"); return; } if (format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX || format == GL_DEPTH_COMPONENT || format == GL_INTENSITY || type == GL_BITMAP) { _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)"); return; } components = _mesa_components_in_format(format); assert(components > 0); /* this should have been caught earlier */ ctx->Convolution2D.Format = format; ctx->Convolution2D.InternalFormat = internalFormat; ctx->Convolution2D.Width = width; ctx->Convolution2D.Height = height; /* Unpack filter image. We always store filters in RGBA format. */ for (i = 0; i < height; i++) { const GLvoid *src = _mesa_image_address(&ctx->Unpack, image, width, height, format, type, 0, i, 0); GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4; _mesa_unpack_float_color_span(ctx, width, GL_RGBA, dst, format, type, src, &ctx->Unpack, 0, GL_FALSE); } /* apply scale and bias */ { const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[1]; const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[1]; for (i = 0; i < width * height; i++) { GLfloat r = ctx->Convolution2D.Filter[i * 4 + 0]; GLfloat g = ctx->Convolution2D.Filter[i * 4 + 1]; GLfloat b = ctx->Convolution2D.Filter[i * 4 + 2]; GLfloat a = ctx->Convolution2D.Filter[i * 4 + 3]; r = r * scale[0] + bias[0]; g = g * scale[1] + bias[1]; b = b * scale[2] + bias[2]; a = a * scale[3] + bias[3]; ctx->Convolution2D.Filter[i * 4 + 0] = r; ctx->Convolution2D.Filter[i * 4 + 1] = g; ctx->Convolution2D.Filter[i * 4 + 2] = b; ctx->Convolution2D.Filter[i * 4 + 3] = a; } } ctx->NewState |= _NEW_PIXEL; }
/* * Render a bitmap. */ void _swrast_Bitmap( GLcontext *ctx, GLint px, GLint py, GLsizei width, GLsizei height, const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); GLint row, col; GLuint count = 0; struct sw_span span; ASSERT(ctx->RenderMode == GL_RENDER); ASSERT(bitmap); RENDER_START(swrast,ctx); if (SWRAST_CONTEXT(ctx)->NewState) _swrast_validate_derived( ctx ); INIT_SPAN(span, GL_BITMAP, width, 0, SPAN_XY); if (ctx->Visual.rgbMode) { span.interpMask |= SPAN_RGBA; span.red = FloatToFixed(ctx->Current.RasterColor[0] * CHAN_MAXF); span.green = FloatToFixed(ctx->Current.RasterColor[1] * CHAN_MAXF); span.blue = FloatToFixed(ctx->Current.RasterColor[2] * CHAN_MAXF); span.alpha = FloatToFixed(ctx->Current.RasterColor[3] * CHAN_MAXF); span.redStep = span.greenStep = span.blueStep = span.alphaStep = 0; } else { span.interpMask |= SPAN_INDEX; span.index = ChanToFixed(ctx->Current.RasterIndex); span.indexStep = 0; } if (ctx->Depth.Test) _mesa_span_default_z(ctx, &span); if (ctx->Fog.Enabled) _mesa_span_default_fog(ctx, &span); if (ctx->Texture._EnabledUnits) _mesa_span_default_texcoords(ctx, &span); for (row = 0; row < height; row++, span.y++) { const GLubyte *src = (const GLubyte *) _mesa_image_address( unpack, bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, 0, row, 0 ); if (unpack->LsbFirst) { /* Lsb first */ GLubyte mask = 1U << (unpack->SkipPixels & 0x7); for (col = 0; col < width; col++) { if (*src & mask) { span.array->x[count] = px + col; span.array->y[count] = py + row; count++; } if (mask == 128U) { src++; mask = 1U; } else { mask = mask << 1; } } /* get ready for next row */ if (mask != 1) src++; } else { /* Msb first */ GLubyte mask = 128U >> (unpack->SkipPixels & 0x7); for (col = 0; col < width; col++) { if (*src & mask) { span.array->x[count] = px + col; span.array->y[count] = py + row; count++; } if (mask == 1U) { src++; mask = 128U; } else { mask = mask >> 1; } } /* get ready for next row */ if (mask != 128) src++; } if (count + width >= MAX_WIDTH || row + 1 == height) { /* flush the span */ span.end = count; if (ctx->Visual.rgbMode) _mesa_write_rgba_span(ctx, &span); else _mesa_write_index_span(ctx, &span); span.end = 0; count = 0; } } RENDER_FINISH(swrast,ctx); }
/** * Store a combined depth/stencil texture image. */ static GLboolean _mesa_texstore_s8_z24(TEXSTORE_PARAMS) { const GLuint depthScale = 0xffffff; const GLint srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType); GLint img, row; GLuint *depth; GLubyte *stencil; assert(dstFormat == MESA_FORMAT_Z24_UNORM_S8_UINT); assert(srcFormat == GL_DEPTH_STENCIL_EXT || srcFormat == GL_DEPTH_COMPONENT || srcFormat == GL_STENCIL_INDEX); assert(srcFormat != GL_DEPTH_STENCIL_EXT || srcType == GL_UNSIGNED_INT_24_8_EXT || srcType == GL_FLOAT_32_UNSIGNED_INT_24_8_REV); depth = malloc(srcWidth * sizeof(GLuint)); stencil = malloc(srcWidth * sizeof(GLubyte)); if (!depth || !stencil) { free(depth); free(stencil); return GL_FALSE; } for (img = 0; img < srcDepth; img++) { GLuint *dstRow = (GLuint *) dstSlices[img]; const GLubyte *src = (const GLubyte *) _mesa_image_address(dims, srcPacking, srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, 0, 0); for (row = 0; row < srcHeight; row++) { GLint i; GLboolean keepdepth = GL_FALSE, keepstencil = GL_FALSE; if (srcFormat == GL_DEPTH_COMPONENT) { /* preserve stencil */ keepstencil = GL_TRUE; } else if (srcFormat == GL_STENCIL_INDEX) { /* preserve depth */ keepdepth = GL_TRUE; } if (keepdepth == GL_FALSE) /* the 24 depth bits will be in the low position: */ _mesa_unpack_depth_span(ctx, srcWidth, GL_UNSIGNED_INT, /* dst type */ keepstencil ? depth : dstRow, /* dst addr */ depthScale, srcType, src, srcPacking); if (keepstencil == GL_FALSE) /* get the 8-bit stencil values */ _mesa_unpack_stencil_span(ctx, srcWidth, GL_UNSIGNED_BYTE, /* dst type */ stencil, /* dst addr */ srcType, src, srcPacking, ctx->_ImageTransferState); /* merge stencil values into depth values */ for (i = 0; i < srcWidth; i++) { if (keepstencil) dstRow[i] = depth[i] | (dstRow[i] & 0xFF000000); else dstRow[i] = (dstRow[i] & 0xFFFFFF) | (stencil[i] << 24); } src += srcRowStride; dstRow += dstRowStride / sizeof(GLuint); } } free(depth); free(stencil); return GL_TRUE; }