/** * Read pixels for format=GL_DEPTH_COMPONENT. */ static void read_depth_pixels( struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, GLvoid *pixels, const struct gl_pixelstore_attrib *packing ) { struct gl_framebuffer *fb = ctx->ReadBuffer; struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; GLint j; GLubyte *dst, *map; int dstStride, stride; GLfloat *depthValues; if (!rb) return; /* clipping should have been done already */ ASSERT(x >= 0); ASSERT(y >= 0); ASSERT(x + width <= (GLint) rb->Width); ASSERT(y + height <= (GLint) rb->Height); if (type == GL_UNSIGNED_INT && read_uint_depth_pixels(ctx, x, y, width, height, type, pixels, packing)) { return; } dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type); dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, GL_DEPTH_COMPONENT, type, 0, 0); ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, &map, &stride); if (!map) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); return; } depthValues = malloc(width * sizeof(GLfloat)); if (depthValues) { /* General case (slower) */ for (j = 0; j < height; j++, y++) { _mesa_unpack_float_z_row(rb->Format, width, map, depthValues); _mesa_pack_depth_span(ctx, width, dst, type, depthValues, packing); dst += dstStride; map += stride; } } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); } free(depthValues); ctx->Driver.UnmapRenderbuffer(ctx, rb); }
/* Extract a rectangle's worth of data from the bitmap. Called * per-cliprect. */ static GLuint get_bitmap_rect(GLsizei width, GLsizei height, const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap, GLuint x, GLuint y, GLuint w, GLuint h, GLubyte *dest, GLuint row_align, GLboolean invert) { GLuint src_offset = (x + unpack->SkipPixels) & 0x7; GLuint mask = unpack->LsbFirst ? 0 : 7; GLuint bit = 0; GLint row, col; GLint first, last; GLint incr; GLuint count = 0; if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s %d,%d %dx%d bitmap %dx%d skip %d src_offset %d mask %d\n", __FUNCTION__, x,y,w,h,width,height,unpack->SkipPixels, src_offset, mask); if (invert) { first = h-1; last = 0; incr = -1; } else { first = 0; last = h-1; incr = 1; } /* Require that dest be pre-zero'd. */ for (row = first; row != (last+incr); row += incr) { const GLubyte *rowsrc = _mesa_image_address2d(unpack, bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, y + row, x); for (col = 0; col < w; col++, bit++) { if (test_bit(rowsrc, (col + src_offset) ^ mask)) { set_bit(dest, bit ^ 7); count++; } } if (row_align) bit = ALIGN(bit, row_align); } return count; }
/** * Store user's image in rgba_dxt1 format. */ GLboolean _mesa_texstore_rgba_dxt1(TEXSTORE_PARAMS) { const GLubyte *pixels; GLubyte *dst; const GLubyte *tempImage = NULL; assert(dstFormat == MESA_FORMAT_RGBA_DXT1 || dstFormat == MESA_FORMAT_SRGBA_DXT1); if (srcFormat != GL_RGBA || srcType != GL_UNSIGNED_BYTE || ctx->_ImageTransferState || ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth || srcPacking->SwapBytes) { /* convert image to RGBA/GLubyte */ GLubyte *tempImageSlices[1]; int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte); tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte)); if (!tempImage) return GL_FALSE; /* out of memory */ tempImageSlices[0] = (GLubyte *) tempImage; _mesa_texstore(ctx, dims, baseInternalFormat, _mesa_little_endian() ? MESA_FORMAT_R8G8B8A8_UNORM : MESA_FORMAT_A8B8G8R8_UNORM, rgbaRowStride, tempImageSlices, srcWidth, srcHeight, srcDepth, srcFormat, srcType, srcAddr, srcPacking); pixels = tempImage; srcFormat = GL_RGBA; } else { pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, srcFormat, srcType, 0, 0); } dst = dstSlices[0]; 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"); } free((void*) tempImage); return GL_TRUE; }
/** * Tries to implement glReadPixels() of GL_DEPTH_COMPONENT using memcpy of the * mapping. */ static GLboolean fast_read_depth_pixels( struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, GLvoid *pixels, const struct gl_pixelstore_attrib *packing ) { struct gl_framebuffer *fb = ctx->ReadBuffer; struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; GLubyte *map, *dst; int stride, dstStride, j; if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0) return GL_FALSE; if (packing->SwapBytes) return GL_FALSE; if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED) return GL_FALSE; if (!((type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16) || type == GL_UNSIGNED_INT)) return GL_FALSE; ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, &map, &stride); if (!map) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); return GL_TRUE; /* don't bother trying the slow path */ } dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type); dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, GL_DEPTH_COMPONENT, type, 0, 0); for (j = 0; j < height; j++) { if (type == GL_UNSIGNED_INT) { _mesa_unpack_uint_z_row(rb->Format, width, map, (GLuint *)dst); } else { ASSERT(type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16); memcpy(dst, map, width * 2); } map += stride; dst += dstStride; } ctx->Driver.UnmapRenderbuffer(ctx, rb); return GL_TRUE; }
/* * Draw color index image. */ static void draw_index_pixels( GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels ) { const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; GLint row, skipPixels; struct sw_span span; INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_INDEX); if (ctx->Depth.Test) _swrast_span_default_z(ctx, &span); if (ctx->Fog.Enabled) _swrast_span_default_fog(ctx, &span); /* * General solution */ skipPixels = 0; while (skipPixels < width) { const GLint spanX = x + (zoom ? 0 : skipPixels); GLint spanY = y; const GLint spanEnd = (width - skipPixels > MAX_WIDTH) ? MAX_WIDTH : (width - skipPixels); ASSERT(spanEnd <= MAX_WIDTH); for (row = 0; row < height; row++, spanY++) { const GLvoid *source = _mesa_image_address2d(unpack, pixels, width, height, GL_COLOR_INDEX, type, row, skipPixels); _mesa_unpack_index_span(ctx, spanEnd, GL_UNSIGNED_INT, span.array->index, type, source, unpack, ctx->_ImageTransferState); /* These may get changed during writing/clipping */ span.x = spanX; span.y = spanY; span.end = spanEnd; if (zoom) _swrast_write_zoomed_index_span(ctx, &span, y, skipPixels); else _swrast_write_index_span(ctx, &span); } skipPixels += spanEnd; } }
static void slow_read_rgba_pixels( struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels, const struct gl_pixelstore_attrib *packing, GLbitfield transferOps ) { struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; const gl_format rbFormat = _mesa_get_srgb_format_linear(rb->Format); void *rgba; GLubyte *dst, *map; int dstStride, stride, j; dstStride = _mesa_image_row_stride(packing, width, format, type); dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, format, type, 0, 0); ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, &map, &stride); if (!map) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); return; } rgba = malloc(width * MAX_PIXEL_BYTES); if (!rgba) goto done; for (j = 0; j < height; j++) { if (_mesa_is_integer_format(format)) { _mesa_unpack_uint_rgba_row(rbFormat, width, map, (GLuint (*)[4]) rgba); _mesa_pack_rgba_span_int(ctx, width, (GLuint (*)[4]) rgba, format, type, dst); } else { _mesa_unpack_rgba_row(rbFormat, width, map, (GLfloat (*)[4]) rgba); _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dst, packing, transferOps); } dst += dstStride; map += stride; } free(rgba); done: ctx->Driver.UnmapRenderbuffer(ctx, rb); }
/** * Store user's image in rgba_dxt1 format. */ GLboolean _mesa_texstore_rgba_dxt1(TEXSTORE_PARAMS) { const GLubyte *pixels; GLubyte *dst; const GLubyte *tempImage = NULL; ASSERT(dstFormat == MESA_FORMAT_RGBA_DXT1 || dstFormat == MESA_FORMAT_SRGBA_DXT1); if (srcFormat != GL_RGBA || srcType != GL_UNSIGNED_BYTE || ctx->_ImageTransferState || srcPacking->RowLength != srcWidth || srcPacking->SwapBytes) { /* convert image to RGBA/GLubyte */ tempImage = _mesa_make_temp_ubyte_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 = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, srcFormat, srcType, 0, 0); } dst = dstSlices[0]; 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"); } free((void*) tempImage); return GL_TRUE; }
/** * Read pixels for format=GL_STENCIL_INDEX. */ static void read_stencil_pixels( struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, GLvoid *pixels, const struct gl_pixelstore_attrib *packing ) { struct gl_framebuffer *fb = ctx->ReadBuffer; struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; GLint j; GLubyte *map, *stencil; GLint stride; if (!rb) return; ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, &map, &stride); if (!map) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); return; } stencil = malloc(width * sizeof(GLubyte)); if (stencil) { /* process image row by row */ for (j = 0; j < height; j++) { GLvoid *dest; _mesa_unpack_ubyte_stencil_row(rb->Format, width, map, stencil); dest = _mesa_image_address2d(packing, pixels, width, height, GL_STENCIL_INDEX, type, j, 0); _mesa_pack_stencil_span(ctx, width, type, dest, stencil, packing); map += stride; } } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); } free(stencil); ctx->Driver.UnmapRenderbuffer(ctx, rb); }
/* * Draw color index image. */ static void draw_index_pixels( GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels ) { const GLint imgX = x, imgY = y; const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; GLint row, skipPixels; SWspan span; INIT_SPAN(span, GL_BITMAP); span.arrayMask = SPAN_INDEX; _swrast_span_default_attribs(ctx, &span); /* * General solution */ skipPixels = 0; while (skipPixels < width) { const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); ASSERT(spanWidth <= MAX_WIDTH); for (row = 0; row < height; row++) { const GLvoid *source = _mesa_image_address2d(unpack, pixels, width, height, GL_COLOR_INDEX, type, row, skipPixels); _mesa_unpack_index_span(ctx, spanWidth, GL_UNSIGNED_INT, span.array->index, type, source, unpack, ctx->_ImageTransferState); /* These may get changed during writing/clipping */ span.x = x + skipPixels; span.y = y + row; span.end = spanWidth; if (zoom) _swrast_write_zoomed_index_span(ctx, imgX, imgY, &span); else _swrast_write_index_span(ctx, &span); } skipPixels += spanWidth; } }
static GLboolean fast_read_rgba_pixels_memcpy( struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels, const struct gl_pixelstore_attrib *packing, GLbitfield transferOps ) { struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; GLubyte *dst, *map; int dstStride, stride, j, texelBytes; if (!_mesa_format_matches_format_and_type(rb->Format, format, type)) return GL_FALSE; /* check for things we can't handle here */ if (packing->SwapBytes || packing->LsbFirst) { return GL_FALSE; } dstStride = _mesa_image_row_stride(packing, width, format, type); dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, format, type, 0, 0); ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, &map, &stride); if (!map) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); return GL_TRUE; /* don't bother trying the slow path */ } texelBytes = _mesa_get_format_bytes(rb->Format); for (j = 0; j < height; j++) { memcpy(dst, map, width * texelBytes); dst += dstStride; map += stride; } ctx->Driver.UnmapRenderbuffer(ctx, rb); return GL_TRUE; }
/** * Handle a common case of drawing GL_RGBA/GL_UNSIGNED_BYTE into a * MESA_FORMAT_ARGB888 or MESA_FORMAT_xRGB888 renderbuffer. */ static void fast_draw_rgba_ubyte_pixels(struct gl_context *ctx, struct gl_renderbuffer *rb, GLint x, GLint y, GLsizei width, GLsizei height, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) { const GLubyte *src = (const GLubyte *) _mesa_image_address2d(unpack, pixels, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0); const GLint srcRowStride = _mesa_image_row_stride(unpack, width, GL_RGBA, GL_UNSIGNED_BYTE); GLint i, j; GLubyte *dst; GLint dstRowStride; ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_WRITE_BIT, &dst, &dstRowStride); if (!dst) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels"); return; } if (ctx->Pixel.ZoomY == -1.0f) { dst = dst + (height - 1) * dstRowStride; dstRowStride = -dstRowStride; } for (i = 0; i < height; i++) { GLuint *dst4 = (GLuint *) dst; for (j = 0; j < width; j++) { dst4[j] = PACK_COLOR_8888(src[j*4+3], src[j*4+0], src[j*4+1], src[j*4+2]); } dst += dstRowStride; src += srcRowStride; } ctx->Driver.UnmapRenderbuffer(ctx, rb); }
/** * Read pixels for format=GL_STENCIL_INDEX. */ static void read_stencil_pixels( struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, GLvoid *pixels, const struct gl_pixelstore_attrib *packing ) { struct gl_framebuffer *fb = ctx->ReadBuffer; struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; GLint j; GLubyte *map; GLint stride; if (!rb) return; /* width should never be > MAX_WIDTH since we did clipping earlier */ ASSERT(width <= MAX_WIDTH); ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, &map, &stride); if (!map) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); return; } /* process image row by row */ for (j = 0; j < height; j++) { GLvoid *dest; GLubyte stencil[MAX_WIDTH]; _mesa_unpack_ubyte_stencil_row(rb->Format, width, map, stencil); dest = _mesa_image_address2d(packing, pixels, width, height, GL_STENCIL_INDEX, type, j, 0); _mesa_pack_stencil_span(ctx, width, type, dest, stencil, packing); map += stride; } ctx->Driver.UnmapRenderbuffer(ctx, rb); }
static GLboolean readpixels_memcpy(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels, const struct gl_pixelstore_attrib *packing) { struct gl_renderbuffer *rb = _mesa_get_read_renderbuffer_for_format(ctx, format); GLubyte *dst, *map; int dstStride, stride, j, texelBytes; /* Fail if memcpy cannot be used. */ if (!readpixels_can_use_memcpy(ctx, format, type, packing)) { return GL_FALSE; } dstStride = _mesa_image_row_stride(packing, width, format, type); dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, format, type, 0, 0); ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, &map, &stride); if (!map) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); return GL_TRUE; /* don't bother trying the slow path */ } texelBytes = _mesa_get_format_bytes(rb->Format); /* memcpy*/ for (j = 0; j < height; j++) { memcpy(dst, map, width * texelBytes); dst += dstStride; map += stride; } ctx->Driver.UnmapRenderbuffer(ctx, rb); return GL_TRUE; }
/** * Handle a common case of drawing a format/type combination that * exactly matches the renderbuffer format. */ static void fast_draw_generic_pixels(struct gl_context *ctx, struct gl_renderbuffer *rb, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) { const GLubyte *src = (const GLubyte *) _mesa_image_address2d(unpack, pixels, width, height, format, type, 0, 0); const GLint srcRowStride = _mesa_image_row_stride(unpack, width, format, type); const GLint rowLength = width * _mesa_get_format_bytes(rb->Format); GLint i; GLubyte *dst; GLint dstRowStride; ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_WRITE_BIT, &dst, &dstRowStride); if (!dst) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels"); return; } if (ctx->Pixel.ZoomY == -1.0f) { dst = dst + (height - 1) * dstRowStride; dstRowStride = -dstRowStride; } for (i = 0; i < height; i++) { memcpy(dst, src, rowLength); dst += dstRowStride; src += srcRowStride; } ctx->Driver.UnmapRenderbuffer(ctx, rb); }
/* * Draw stencil image. */ static void draw_stencil_pixels( struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels ) { const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; const GLenum destType = GL_UNSIGNED_BYTE; GLint row; GLubyte *values; values = malloc(width * sizeof(GLubyte)); if (!values) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels"); return; } for (row = 0; row < height; row++) { const GLvoid *source = _mesa_image_address2d(unpack, pixels, width, height, GL_STENCIL_INDEX, type, row, 0); _mesa_unpack_stencil_span(ctx, width, destType, values, type, source, unpack, ctx->_ImageTransferState); if (zoom) { _swrast_write_zoomed_stencil_span(ctx, x, y, width, x, y, values); } else { _swrast_write_stencil_span(ctx, width, x, y, values); } y++; } free(values); }
/* * Draw stencil image. */ static void draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels ) { const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; GLint skipPixels; /* if width > MAX_WIDTH, have to process image in chunks */ skipPixels = 0; while (skipPixels < width) { const GLint spanX = x + skipPixels; const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); GLint row; for (row = 0; row < height; row++) { const GLint spanY = y + row; GLstencil values[MAX_WIDTH]; GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte)) ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT; const GLvoid *source = _mesa_image_address2d(unpack, pixels, width, height, GL_COLOR_INDEX, type, row, skipPixels); _mesa_unpack_stencil_span(ctx, spanWidth, destType, values, type, source, unpack, ctx->_ImageTransferState); if (zoom) { _swrast_write_zoomed_stencil_span(ctx, x, y, spanWidth, spanX, spanY, values); } else { _swrast_write_stencil_span(ctx, spanWidth, spanX, spanY, values); } } skipPixels += spanWidth; } }
/** * Read combined depth/stencil values. * We'll have already done error checking to be sure the expected * depth and stencil buffers really exist. */ static void read_depth_stencil_pixels(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, GLvoid *pixels, const struct gl_pixelstore_attrib *packing ) { const GLboolean scaleOrBias = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0; const GLboolean stencilTransfer = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset || ctx->Pixel.MapStencilFlag; GLubyte *dst; int dstStride; dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, GL_DEPTH_STENCIL_EXT, type, 0, 0); dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_STENCIL_EXT, type); /* Fast 24/8 reads. */ if (type == GL_UNSIGNED_INT_24_8 && !scaleOrBias && !stencilTransfer && !packing->SwapBytes) { if (fast_read_depth_stencil_pixels(ctx, x, y, width, height, dst, dstStride)) return; if (fast_read_depth_stencil_pixels_separate(ctx, x, y, width, height, (uint32_t *)dst, dstStride)) return; } slow_read_depth_stencil_pixels_separate(ctx, x, y, width, height, type, packing, dst, dstStride); }
/* * Draw stencil image. */ static void draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels ) { const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; const GLint desty = y; GLint row, skipPixels; if (type != GL_BYTE && type != GL_UNSIGNED_BYTE && type != GL_SHORT && type != GL_UNSIGNED_SHORT && type != GL_INT && type != GL_UNSIGNED_INT && type != GL_FLOAT && type != GL_BITMAP) { _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(stencil type)"); return; } if (ctx->Visual.stencilBits == 0) { _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawPixels(no stencil buffer)"); return; } /* if width > MAX_WIDTH, have to process image in chunks */ skipPixels = 0; while (skipPixels < width) { const GLint spanX = x; GLint spanY = y; const GLint spanWidth = (width - skipPixels > MAX_WIDTH) ? MAX_WIDTH : (width - skipPixels); for (row = 0; row < height; row++, spanY++) { GLstencil values[MAX_WIDTH]; GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte)) ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT; const GLvoid *source = _mesa_image_address2d(unpack, pixels, width, height, GL_COLOR_INDEX, type, row, skipPixels); _mesa_unpack_index_span(ctx, spanWidth, destType, values, type, source, unpack, ctx->_ImageTransferState); if (ctx->_ImageTransferState & IMAGE_SHIFT_OFFSET_BIT) { _mesa_shift_and_offset_stencil(ctx, spanWidth, values); } if (ctx->Pixel.MapStencilFlag) { _mesa_map_stencil(ctx, spanWidth, values); } if (zoom) { _swrast_write_zoomed_stencil_span(ctx, (GLuint) spanWidth, spanX, spanY, values, desty, 0); } else { _swrast_write_stencil_span(ctx, (GLuint) spanWidth, spanX, spanY, values); } } skipPixels += spanWidth; } }
/** * glGetTexImage() helper: decompress a compressed texture by rendering * a textured quad. Store the results in the user's buffer. */ static void decompress_with_blit(struct gl_context * ctx, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct st_texture_image *stImage = st_texture_image(texImage); struct st_texture_object *stObj = st_texture_object(texImage->TexObject); const GLuint width = texImage->Width; const GLuint height = texImage->Height; struct pipe_resource *dst_texture; struct pipe_blit_info blit; unsigned bind = (PIPE_BIND_RENDER_TARGET | PIPE_BIND_TRANSFER_READ); struct pipe_transfer *tex_xfer; ubyte *map; /* create temp / dest surface */ if (!util_create_rgba_texture(pipe, width, height, bind, &dst_texture)) { _mesa_problem(ctx, "util_create_rgba_texture() failed " "in decompress_with_blit()"); return; } blit.src.resource = stObj->pt; blit.src.level = texImage->Level; blit.src.format = util_format_linear(stObj->pt->format); blit.dst.resource = dst_texture; blit.dst.level = 0; blit.dst.format = dst_texture->format; blit.src.box.x = blit.dst.box.x = 0; blit.src.box.y = blit.dst.box.y = 0; blit.src.box.z = 0; /* XXX compressed array textures? */ blit.dst.box.z = 0; blit.src.box.width = blit.dst.box.width = width; blit.src.box.height = blit.dst.box.height = height; blit.src.box.depth = blit.dst.box.depth = 1; blit.mask = PIPE_MASK_RGBA; blit.filter = PIPE_TEX_FILTER_NEAREST; blit.scissor_enable = FALSE; /* blit/render/decompress */ st->pipe->blit(st->pipe, &blit); pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels); map = pipe_transfer_map(pipe, dst_texture, 0, 0, PIPE_TRANSFER_READ, 0, 0, width, height, &tex_xfer); if (!map) { goto end; } /* copy/pack data into user buffer */ if (_mesa_format_matches_format_and_type(stImage->base.TexFormat, format, type, ctx->Pack.SwapBytes)) { /* memcpy */ const uint bytesPerRow = width * util_format_get_blocksize(stImage->pt->format); /* map the dst_surface so we can read from it */ GLuint row; for (row = 0; row < height; row++) { GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, height, format, type, row, 0); memcpy(dest, map, bytesPerRow); map += tex_xfer->stride; } pipe_transfer_unmap(pipe, tex_xfer); } else { /* format translation via floats */ GLuint row; enum pipe_format pformat = util_format_linear(dst_texture->format); GLfloat *rgba; rgba = malloc(width * 4 * sizeof(GLfloat)); if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); goto end; } for (row = 0; row < height; row++) { const GLbitfield transferOps = 0x0; /* bypassed for glGetTexImage() */ GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, height, format, type, row, 0); if (ST_DEBUG & DEBUG_FALLBACK) debug_printf("%s: fallback format translation\n", __FUNCTION__); /* get float[4] rgba row from surface */ pipe_get_tile_rgba_format(tex_xfer, map, 0, row, width, 1, pformat, rgba); _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dest, &ctx->Pack, transferOps); } free(rgba); } end: if (map) pipe_transfer_unmap(pipe, tex_xfer); _mesa_unmap_pbo_dest(ctx, &ctx->Pack); pipe_resource_reference(&dst_texture, NULL); }
/** * Try to do glGetTexImage() with simple memcpy(). * \return GL_TRUE if done, GL_FALSE otherwise */ static GLboolean get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage) { const GLenum target = texImage->TexObject->Target; GLboolean memCopy = GL_FALSE; /* * Check if we can use memcpy to copy from the hardware texture * format to the user's format/type. * Note that GL's pixel transfer ops don't apply to glGetTexImage() */ if (target == GL_TEXTURE_1D || target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE || _mesa_is_cube_face(target)) { memCopy = _mesa_format_matches_format_and_type(texImage->TexFormat, format, type, ctx->Pack.SwapBytes); } if (memCopy) { const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat); const GLuint bytesPerRow = texImage->Width * bpp; GLubyte *dst = _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width, texImage->Height, format, type, 0, 0); const GLint dstRowStride = _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type); GLubyte *src; GLint srcRowStride; /* map src texture buffer */ ctx->Driver.MapTextureImage(ctx, texImage, 0, 0, 0, texImage->Width, texImage->Height, GL_MAP_READ_BIT, &src, &srcRowStride); if (src) { if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) { memcpy(dst, src, bytesPerRow * texImage->Height); } else { GLuint row; for (row = 0; row < texImage->Height; row++) { memcpy(dst, src, bytesPerRow); dst += dstRowStride; src += srcRowStride; } } /* unmap src texture buffer */ ctx->Driver.UnmapTextureImage(ctx, texImage, 0); } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); } } return memCopy; }
/* * Draw depth image. */ static void draw_depth_pixels( GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels ) { const GLboolean bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; const GLint desty = y; struct sw_span span; INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_Z); if (type != GL_BYTE && type != GL_UNSIGNED_BYTE && type != GL_SHORT && type != GL_UNSIGNED_SHORT && type != GL_INT && type != GL_UNSIGNED_INT && type != GL_FLOAT) { _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)"); return; } _swrast_span_default_color(ctx, &span); if (ctx->Fog.Enabled) _swrast_span_default_fog(ctx, &span); if (ctx->Texture._EnabledCoordUnits) _swrast_span_default_texcoords(ctx, &span); if (type == GL_UNSIGNED_SHORT && ctx->Visual.depthBits == 16 && !bias_or_scale && !zoom && ctx->Visual.rgbMode && width <= MAX_WIDTH) { /* Special case: directly write 16-bit depth values */ GLint row, spanY = y; for (row = 0; row < height; row++, spanY++) { const GLushort *zSrc = (const GLushort *) _mesa_image_address2d(unpack, pixels, width, height, GL_DEPTH_COMPONENT, type, row, 0); GLint i; for (i = 0; i < width; i++) span.array->z[i] = zSrc[i]; span.x = x; span.y = spanY; span.end = width; _swrast_write_rgba_span(ctx, &span); } } else if (type == GL_UNSIGNED_INT && sizeof(GLdepth) == 4 && !bias_or_scale && !zoom && ctx->Visual.rgbMode && width <= MAX_WIDTH) { /* Special case: shift 32-bit values down to ctx->Visual.depthBits */ const GLint shift = 32 - ctx->Visual.depthBits; GLint row, spanY = y; for (row = 0; row < height; row++, spanY++) { const GLuint *zSrc = (const GLuint *) _mesa_image_address2d(unpack, pixels, width, height, GL_DEPTH_COMPONENT, type, row, 0); if (shift == 0) { MEMCPY(span.array->z, zSrc, width * sizeof(GLdepth)); } else { GLint col; for (col = 0; col < width; col++) span.array->z[col] = zSrc[col] >> shift; } span.x = x; span.y = spanY; span.end = width; _swrast_write_rgba_span(ctx, &span); } } else {
/** * 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(pipe, strb->texture, strb->rtt_level, strb->rtt_face + strb->rtt_slice, 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); }
/* * Draw depth image. */ static void draw_depth_pixels( struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels ) { const GLboolean scaleOrBias = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; SWspan span; INIT_SPAN(span, GL_BITMAP); span.arrayMask = SPAN_Z; _swrast_span_default_attribs(ctx, &span); if (type == GL_UNSIGNED_SHORT && ctx->DrawBuffer->Visual.depthBits == 16 && !scaleOrBias && !zoom && width <= SWRAST_MAX_WIDTH && !unpack->SwapBytes) { /* Special case: directly write 16-bit depth values */ GLint row; for (row = 0; row < height; row++) { const GLushort *zSrc = (const GLushort *) _mesa_image_address2d(unpack, pixels, width, height, GL_DEPTH_COMPONENT, type, row, 0); GLint i; for (i = 0; i < width; i++) span.array->z[i] = zSrc[i]; span.x = x; span.y = y + row; span.end = width; _swrast_write_rgba_span(ctx, &span); } } else if (type == GL_UNSIGNED_INT && !scaleOrBias && !zoom && width <= SWRAST_MAX_WIDTH && !unpack->SwapBytes) { /* Special case: shift 32-bit values down to Visual.depthBits */ const GLint shift = 32 - ctx->DrawBuffer->Visual.depthBits; GLint row; for (row = 0; row < height; row++) { const GLuint *zSrc = (const GLuint *) _mesa_image_address2d(unpack, pixels, width, height, GL_DEPTH_COMPONENT, type, row, 0); if (shift == 0) { memcpy(span.array->z, zSrc, width * sizeof(GLuint)); } else { GLint col; for (col = 0; col < width; col++) span.array->z[col] = zSrc[col] >> shift; } span.x = x; span.y = y + row; span.end = width; _swrast_write_rgba_span(ctx, &span); } } else {
/** * Try to do a fast and simple RGB(a) glDrawPixels. * Return: GL_TRUE if success, GL_FALSE if slow path must be used instead */ static GLboolean fast_draw_rgba_pixels(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *userUnpack, const GLvoid *pixels) { const GLint imgX = x, imgY = y; struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; GLenum rbType; SWcontext *swrast = SWRAST_CONTEXT(ctx); SWspan span; GLboolean simpleZoom; GLint yStep; /* +1 or -1 */ struct gl_pixelstore_attrib unpack; GLint destX, destY, drawWidth, drawHeight; /* post clipping */ if (!rb) return GL_TRUE; /* no-op */ rbType = rb->DataType; if ((swrast->_RasterMask & ~CLIP_BIT) || ctx->Texture._EnabledCoordUnits || userUnpack->SwapBytes || ctx->_ImageTransferState) { /* can't handle any of those conditions */ return GL_FALSE; } INIT_SPAN(span, GL_BITMAP); span.arrayMask = SPAN_RGBA; span.arrayAttribs = FRAG_BIT_COL0; _swrast_span_default_attribs(ctx, &span); /* copy input params since clipping may change them */ unpack = *userUnpack; destX = x; destY = y; drawWidth = width; drawHeight = height; /* check for simple zooming and clipping */ if (ctx->Pixel.ZoomX == 1.0F && (ctx->Pixel.ZoomY == 1.0F || ctx->Pixel.ZoomY == -1.0F)) { if (!_mesa_clip_drawpixels(ctx, &destX, &destY, &drawWidth, &drawHeight, &unpack)) { /* image was completely clipped: no-op, all done */ return GL_TRUE; } simpleZoom = GL_TRUE; yStep = (GLint) ctx->Pixel.ZoomY; ASSERT(yStep == 1 || yStep == -1); } else { /* non-simple zooming */ simpleZoom = GL_FALSE; yStep = 1; if (unpack.RowLength == 0) unpack.RowLength = width; } /* * Ready to draw! */ if (format == GL_RGBA && type == rbType) { const GLubyte *src = (const GLubyte *) _mesa_image_address2d(&unpack, pixels, width, height, format, type, 0, 0); const GLint srcStride = _mesa_image_row_stride(&unpack, width, format, type); if (simpleZoom) { GLint row; for (row = 0; row < drawHeight; row++) { rb->PutRow(ctx, rb, drawWidth, destX, destY, src, NULL); src += srcStride; destY += yStep; } } else { /* with zooming */ GLint row; for (row = 0; row < drawHeight; row++) { span.x = destX; span.y = destY + row; span.end = drawWidth; span.array->ChanType = rbType; _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, src); src += srcStride; } span.array->ChanType = CHAN_TYPE; } return GL_TRUE; } if (format == GL_RGB && type == rbType) { const GLubyte *src = (const GLubyte *) _mesa_image_address2d(&unpack, pixels, width, height, format, type, 0, 0); const GLint srcStride = _mesa_image_row_stride(&unpack, width, format, type); if (simpleZoom) { GLint row; for (row = 0; row < drawHeight; row++) { rb->PutRowRGB(ctx, rb, drawWidth, destX, destY, src, NULL); src += srcStride; destY += yStep; } } else { /* with zooming */ GLint row; for (row = 0; row < drawHeight; row++) { span.x = destX; span.y = destY; span.end = drawWidth; span.array->ChanType = rbType; _swrast_write_zoomed_rgb_span(ctx, imgX, imgY, &span, src); src += srcStride; destY++; } span.array->ChanType = CHAN_TYPE; } return GL_TRUE; } /* Remaining cases haven't been tested with alignment != 1 */ if (userUnpack->Alignment != 1) return GL_FALSE; if (format == GL_LUMINANCE && type == CHAN_TYPE && rbType == CHAN_TYPE) { const GLchan *src = (const GLchan *) pixels + (unpack.SkipRows * unpack.RowLength + unpack.SkipPixels); if (simpleZoom) { /* no zooming */ GLint row; ASSERT(drawWidth <= MAX_WIDTH); for (row = 0; row < drawHeight; row++) { GLchan rgb[MAX_WIDTH][3]; GLint i; for (i = 0;i<drawWidth;i++) { rgb[i][0] = src[i]; rgb[i][1] = src[i]; rgb[i][2] = src[i]; } rb->PutRowRGB(ctx, rb, drawWidth, destX, destY, rgb, NULL); src += unpack.RowLength; destY += yStep; } } else { /* with zooming */ GLint row; ASSERT(drawWidth <= MAX_WIDTH); for (row = 0; row < drawHeight; row++) { GLchan rgb[MAX_WIDTH][3]; GLint i; for (i = 0;i<drawWidth;i++) { rgb[i][0] = src[i]; rgb[i][1] = src[i]; rgb[i][2] = src[i]; } span.x = destX; span.y = destY; span.end = drawWidth; _swrast_write_zoomed_rgb_span(ctx, imgX, imgY, &span, rgb); src += unpack.RowLength; destY++; } } return GL_TRUE; } if (format == GL_LUMINANCE_ALPHA && type == CHAN_TYPE && rbType == CHAN_TYPE) { const GLchan *src = (const GLchan *) pixels + (unpack.SkipRows * unpack.RowLength + unpack.SkipPixels)*2; if (simpleZoom) { GLint row; ASSERT(drawWidth <= MAX_WIDTH); for (row = 0; row < drawHeight; row++) { GLint i; const GLchan *ptr = src; for (i = 0;i<drawWidth;i++) { span.array->rgba[i][0] = *ptr; span.array->rgba[i][1] = *ptr; span.array->rgba[i][2] = *ptr++; span.array->rgba[i][3] = *ptr++; } rb->PutRow(ctx, rb, drawWidth, destX, destY, span.array->rgba, NULL); src += unpack.RowLength*2; destY += yStep; } } else { /* with zooming */ GLint row; ASSERT(drawWidth <= MAX_WIDTH); for (row = 0; row < drawHeight; row++) { const GLchan *ptr = src; GLint i; for (i = 0;i<drawWidth;i++) { span.array->rgba[i][0] = *ptr; span.array->rgba[i][1] = *ptr; span.array->rgba[i][2] = *ptr++; span.array->rgba[i][3] = *ptr++; } span.x = destX; span.y = destY; span.end = drawWidth; _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, span.array->rgba); src += unpack.RowLength*2; destY++; } } return GL_TRUE; } if (format == GL_COLOR_INDEX && type == GL_UNSIGNED_BYTE) { const GLubyte *src = (const GLubyte *) pixels + unpack.SkipRows * unpack.RowLength + unpack.SkipPixels; if (rbType == GL_UNSIGNED_BYTE) { /* convert ubyte/CI data to ubyte/RGBA */ if (simpleZoom) { GLint row; for (row = 0; row < drawHeight; row++) { ASSERT(drawWidth <= MAX_WIDTH); _mesa_map_ci8_to_rgba8(ctx, drawWidth, src, span.array->rgba8); rb->PutRow(ctx, rb, drawWidth, destX, destY, span.array->rgba8, NULL); src += unpack.RowLength; destY += yStep; } } else { /* ubyte/CI to ubyte/RGBA with zooming */ GLint row; for (row = 0; row < drawHeight; row++) { ASSERT(drawWidth <= MAX_WIDTH); _mesa_map_ci8_to_rgba8(ctx, drawWidth, src, span.array->rgba8); span.x = destX; span.y = destY; span.end = drawWidth; _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, span.array->rgba8); src += unpack.RowLength; destY++; } } return GL_TRUE; } } /* can't handle this pixel format and/or data type */ return GL_FALSE; }
/** * glGetTexImage() helper: decompress a compressed texture by rendering * a textured quad. Store the results in the user's buffer. */ static void decompress_with_blit(struct gl_context * ctx, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct st_texture_image *stImage = st_texture_image(texImage); struct st_texture_object *stObj = st_texture_object(texImage->TexObject); struct pipe_sampler_view *src_view; const GLuint width = texImage->Width; const GLuint height = texImage->Height; struct pipe_surface *dst_surface; struct pipe_resource *dst_texture; struct pipe_transfer *tex_xfer; unsigned bind = (PIPE_BIND_RENDER_TARGET | /* util_blit may choose to render */ PIPE_BIND_TRANSFER_READ); /* create temp / dest surface */ if (!util_create_rgba_surface(pipe, width, height, bind, &dst_texture, &dst_surface)) { _mesa_problem(ctx, "util_create_rgba_surface() failed " "in decompress_with_blit()"); return; } /* Disable conditional rendering. */ if (st->render_condition) { pipe->render_condition(pipe, NULL, 0); } /* Create sampler view that limits fetches to the source mipmap level */ { struct pipe_sampler_view sv_temp; u_sampler_view_default_template(&sv_temp, stObj->pt, stObj->pt->format); sv_temp.format = util_format_linear(sv_temp.format); sv_temp.u.tex.first_level = sv_temp.u.tex.last_level = texImage->Level; src_view = pipe->create_sampler_view(pipe, stObj->pt, &sv_temp); if (!src_view) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); return; } } /* blit/render/decompress */ util_blit_pixels_tex(st->blit, src_view, /* pipe_resource (src) */ 0, 0, /* src x0, y0 */ width, height, /* src x1, y1 */ dst_surface, /* pipe_surface (dst) */ 0, 0, /* dst x0, y0 */ width, height, /* dst x1, y1 */ 0.0, /* z */ PIPE_TEX_MIPFILTER_NEAREST); /* Restore conditional rendering state. */ if (st->render_condition) { pipe->render_condition(pipe, st->render_condition, st->condition_mode); } /* map the dst_surface so we can read from it */ tex_xfer = pipe_get_transfer(pipe, dst_texture, 0, 0, PIPE_TRANSFER_READ, 0, 0, width, height); pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels); /* copy/pack data into user buffer */ if (_mesa_format_matches_format_and_type(stImage->base.TexFormat, format, type, ctx->Pack.SwapBytes)) { /* memcpy */ const uint bytesPerRow = width * util_format_get_blocksize(stImage->pt->format); ubyte *map = pipe_transfer_map(pipe, tex_xfer); GLuint row; for (row = 0; row < height; row++) { GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, height, format, type, row, 0); memcpy(dest, map, bytesPerRow); map += tex_xfer->stride; } pipe_transfer_unmap(pipe, tex_xfer); } else { /* format translation via floats */ GLuint row; enum pipe_format pformat = util_format_linear(dst_texture->format); GLfloat *rgba; rgba = (GLfloat *) malloc(width * 4 * sizeof(GLfloat)); if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); goto end; } for (row = 0; row < height; row++) { const GLbitfield transferOps = 0x0; /* bypassed for glGetTexImage() */ GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, height, format, type, row, 0); if (ST_DEBUG & DEBUG_FALLBACK) debug_printf("%s: fallback format translation\n", __FUNCTION__); /* get float[4] rgba row from surface */ pipe_get_tile_rgba_format(pipe, tex_xfer, 0, row, width, 1, pformat, rgba); _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dest, &ctx->Pack, transferOps); } free(rgba); } end: _mesa_unmap_pbo_dest(ctx, &ctx->Pack); pipe->transfer_destroy(pipe, tex_xfer); /* destroy the temp / dest surface */ util_destroy_rgba_surface(dst_texture, dst_surface); pipe_sampler_view_release(pipe, &src_view); }
/* * Read R, G, B, A, RGB, L, or LA pixels. */ static void read_rgba_pixels( struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels, const struct gl_pixelstore_attrib *packing ) { GLbitfield transferOps; bool dst_is_integer, dst_is_luminance, needs_rebase; int dst_stride, src_stride, rb_stride; uint32_t dst_format, src_format; GLubyte *dst, *map; mesa_format rb_format; bool needs_rgba; void *rgba, *src; bool src_is_uint = false; uint8_t rebase_swizzle[4]; struct gl_framebuffer *fb = ctx->ReadBuffer; struct gl_renderbuffer *rb = fb->_ColorReadBuffer; if (!rb) return; transferOps = get_readpixels_transfer_ops(ctx, rb->Format, format, type, GL_FALSE); /* Describe the dst format */ dst_is_integer = _mesa_is_enum_format_integer(format); dst_stride = _mesa_image_row_stride(packing, width, format, type); dst_format = _mesa_format_from_format_and_type(format, type); dst_is_luminance = format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA || format == GL_LUMINANCE_INTEGER_EXT || format == GL_LUMINANCE_ALPHA_INTEGER_EXT; dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, format, type, 0, 0); /* Map the source render buffer */ ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, &map, &rb_stride); if (!map) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); return; } rb_format = _mesa_get_srgb_format_linear(rb->Format); /* * Depending on the base formats involved in the conversion we might need to * rebase some values, so for these formats we compute a rebase swizzle. */ if (rb->_BaseFormat == GL_LUMINANCE || rb->_BaseFormat == GL_INTENSITY) { needs_rebase = true; rebase_swizzle[0] = MESA_FORMAT_SWIZZLE_X; rebase_swizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; rebase_swizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; rebase_swizzle[3] = MESA_FORMAT_SWIZZLE_ONE; } else if (rb->_BaseFormat == GL_LUMINANCE_ALPHA) { needs_rebase = true; rebase_swizzle[0] = MESA_FORMAT_SWIZZLE_X; rebase_swizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; rebase_swizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; rebase_swizzle[3] = MESA_FORMAT_SWIZZLE_W; } else if (_mesa_get_format_base_format(rb_format) != rb->_BaseFormat) { needs_rebase = _mesa_compute_rgba2base2rgba_component_mapping(rb->_BaseFormat, rebase_swizzle); } else { needs_rebase = false; } /* Since _mesa_format_convert does not handle transferOps we need to handle * them before we call the function. This requires to convert to RGBA float * first so we can call _mesa_apply_rgba_transfer_ops. If the dst format is * integer transferOps do not apply. * * Converting to luminance also requires converting to RGBA first, so we can * then compute luminance values as L=R+G+B. Notice that this is different * from GetTexImage, where we compute L=R. */ assert(!transferOps || (transferOps && !dst_is_integer)); needs_rgba = transferOps || dst_is_luminance; rgba = NULL; if (needs_rgba) { uint32_t rgba_format; int rgba_stride; bool need_convert; /* Convert to RGBA float or int/uint depending on the type of the src */ if (dst_is_integer) { src_is_uint = _mesa_is_format_unsigned(rb_format); if (src_is_uint) { rgba_format = RGBA32_UINT; rgba_stride = width * 4 * sizeof(GLuint); } else { rgba_format = RGBA32_INT; rgba_stride = width * 4 * sizeof(GLint); } } else { rgba_format = RGBA32_FLOAT; rgba_stride = width * 4 * sizeof(GLfloat); } /* If we are lucky and the dst format matches the RGBA format we need to * convert to, then we can convert directly into the dst buffer and avoid * the final conversion/copy from the rgba buffer to the dst buffer. */ if (dst_format == rgba_format) { need_convert = false; rgba = dst; } else { need_convert = true; rgba = malloc(height * rgba_stride); if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); goto done_unmap; } } /* Convert to RGBA now */ _mesa_format_convert(rgba, rgba_format, rgba_stride, map, rb_format, rb_stride, width, height, needs_rebase ? rebase_swizzle : NULL); /* Handle transfer ops if necessary */ if (transferOps) _mesa_apply_rgba_transfer_ops(ctx, transferOps, width * height, rgba); /* If we had to rebase, we have already taken care of that */ needs_rebase = false; /* If we were lucky and our RGBA conversion matches the dst format, then * we are done. */ if (!need_convert) goto done_swap; /* Otherwise, we need to convert from RGBA to dst next */ src = rgba; src_format = rgba_format; src_stride = rgba_stride; } else { /* No RGBA conversion needed, convert directly to dst */ src = map; src_format = rb_format; src_stride = rb_stride; } /* Do the conversion. * * If the dst format is Luminance, we need to do the conversion by computing * L=R+G+B values. */ if (!dst_is_luminance) { _mesa_format_convert(dst, dst_format, dst_stride, src, src_format, src_stride, width, height, needs_rebase ? rebase_swizzle : NULL); } else if (!dst_is_integer) { /* Compute float Luminance values from RGBA float */ int luminance_stride, luminance_bytes; void *luminance; uint32_t luminance_format; luminance_stride = width * sizeof(GL_FLOAT); if (format == GL_LUMINANCE_ALPHA) luminance_stride *= 2; luminance_bytes = height * luminance_stride; luminance = malloc(luminance_bytes); if (!luminance) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); free(rgba); goto done_unmap; } _mesa_pack_luminance_from_rgba_float(width * height, src, luminance, format, transferOps); /* Convert from Luminance float to dst (this will hadle type conversion * from float to the type of dst if necessary) */ luminance_format = _mesa_format_from_format_and_type(format, GL_FLOAT); _mesa_format_convert(dst, dst_format, dst_stride, luminance, luminance_format, luminance_stride, width, height, NULL); } else { _mesa_pack_luminance_from_rgba_integer(width * height, src, !src_is_uint, dst, format, type); } if (rgba) free(rgba); done_swap: /* Handle byte swapping if required */ if (packing->SwapBytes) { int components = _mesa_components_in_format(format); GLint swapSize = _mesa_sizeof_packed_type(type); if (swapSize == 2) _mesa_swap2((GLushort *) dst, width * height * components); else if (swapSize == 4) _mesa_swap4((GLuint *) dst, width * height * components); } done_unmap: ctx->Driver.UnmapRenderbuffer(ctx, rb); }
/** * Try to do glGetTexImage() with simple memcpy(). * \return GL_TRUE if done, GL_FALSE otherwise */ static GLboolean get_tex_memcpy(GLcontext *ctx, GLenum format, GLenum type, GLvoid *pixels, const struct gl_texture_object *texObj, const struct gl_texture_image *texImage) { GLboolean memCopy = GL_FALSE; /* Texture image should have been mapped already */ assert(texImage->Data); /* * Check if the src/dst formats are compatible. * Also note that GL's pixel transfer ops don't apply to glGetTexImage() * so we don't have to worry about those. * XXX more format combinations could be supported here. */ if ((texObj->Target == GL_TEXTURE_1D || texObj->Target == GL_TEXTURE_2D || texObj->Target == GL_TEXTURE_RECTANGLE || (texObj->Target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && texObj->Target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))) { if (texImage->TexFormat == MESA_FORMAT_ARGB8888 && format == GL_BGRA && type == GL_UNSIGNED_BYTE && !ctx->Pack.SwapBytes && _mesa_little_endian()) { memCopy = GL_TRUE; } else if (texImage->TexFormat == MESA_FORMAT_AL88 && format == GL_LUMINANCE_ALPHA && type == GL_UNSIGNED_BYTE && !ctx->Pack.SwapBytes && _mesa_little_endian()) { memCopy = GL_TRUE; } else if (texImage->TexFormat == MESA_FORMAT_L8 && format == GL_LUMINANCE && type == GL_UNSIGNED_BYTE) { memCopy = GL_TRUE; } else if (texImage->TexFormat == MESA_FORMAT_A8 && format == GL_ALPHA && type == GL_UNSIGNED_BYTE) { memCopy = GL_TRUE; } } if (memCopy) { const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat); const GLuint bytesPerRow = texImage->Width * bpp; GLubyte *dst = _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width, texImage->Height, format, type, 0, 0); const GLint dstRowStride = _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type); const GLubyte *src = texImage->Data; const GLint srcRowStride = texImage->RowStride * bpp; GLuint row; if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) { memcpy(dst, src, bytesPerRow * texImage->Height); } else { for (row = 0; row < texImage->Height; row++) { memcpy(dst, src, bytesPerRow); dst += dstRowStride; src += srcRowStride; } } } return memCopy; }
/** * Render a bitmap. * Called via ctx->Driver.Bitmap() * All parameter error checking will have been done before this is called. */ void _swrast_Bitmap( struct gl_context *ctx, GLint px, GLint py, GLsizei width, GLsizei height, const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap ) { GLint row, col; GLuint count = 0; SWspan span; ASSERT(ctx->RenderMode == GL_RENDER); if (!_mesa_check_conditional_render(ctx)) return; /* don't draw */ bitmap = (const GLubyte *) _mesa_map_pbo_source(ctx, unpack, bitmap); if (!bitmap) return; swrast_render_start(ctx); if (SWRAST_CONTEXT(ctx)->NewState) _swrast_validate_derived( ctx ); INIT_SPAN(span, GL_BITMAP); span.end = width; span.arrayMask = SPAN_XY; _swrast_span_default_attribs(ctx, &span); for (row = 0; row < height; row++) { const GLubyte *src = (const GLubyte *) _mesa_image_address2d(unpack, bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, 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 >= SWRAST_MAX_WIDTH || row + 1 == height) { /* flush the span */ span.end = count; _swrast_write_rgba_span(ctx, &span); span.end = 0; count = 0; } } swrast_render_finish(ctx); _mesa_unmap_pbo_source(ctx, unpack); }
/* * XXX this is another way to implement Bitmap. Use horizontal runs of * fragments, initializing the mask array to indicate which fragments to * draw or skip. */ void _swrast_Bitmap( struct gl_context *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; SWspan span; ASSERT(ctx->RenderMode == GL_RENDER); ASSERT(bitmap); swrast_render_start(ctx); if (SWRAST_CONTEXT(ctx)->NewState) _swrast_validate_derived( ctx ); INIT_SPAN(span, GL_BITMAP); span.end = width; span.arrayMask = SPAN_MASK; _swrast_span_default_attribs(ctx, &span); /*span.arrayMask |= SPAN_MASK;*/ /* we'll init span.mask[] */ span.x = px; span.y = py; /*span.end = width;*/ for (row=0; row<height; row++, span.y++) { const GLubyte *src = (const GLubyte *) _mesa_image_address2d(unpack, bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, row, 0); if (unpack->LsbFirst) { /* Lsb first */ GLubyte mask = 1U << (unpack->SkipPixels & 0x7); for (col=0; col<width; col++) { span.array->mask[col] = (*src & mask) ? GL_TRUE : GL_FALSE; if (mask == 128U) { src++; mask = 1U; } else { mask = mask << 1; } } _swrast_write_rgba_span(ctx, &span); /* get ready for next row */ if (mask != 1) src++; } else { /* Msb first */ GLubyte mask = 128U >> (unpack->SkipPixels & 0x7); for (col=0; col<width; col++) { span.array->mask[col] = (*src & mask) ? GL_TRUE : GL_FALSE; if (mask == 1U) { src++; mask = 128U; } else { mask = mask >> 1; } } _swrast_write_rgba_span(ctx, &span); /* get ready for next row */ if (mask != 128) src++; } } swrast_render_finish(ctx); }
/** * Try to do glGetTexImage() with simple memcpy(). * \return GL_TRUE if done, GL_FALSE otherwise */ static GLboolean get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage) { const GLenum target = texImage->TexObject->Target; GLboolean memCopy = GL_FALSE; /* * Check if the src/dst formats are compatible. * Also note that GL's pixel transfer ops don't apply to glGetTexImage() * so we don't have to worry about those. * XXX more format combinations could be supported here. */ if (target == GL_TEXTURE_1D || target == GL_TEXTURE_2D || _mesa_is_cube_face(target)) { if ((texImage->TexFormat == MESA_FORMAT_ARGB8888) && format == GL_BGRA && (type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT_8_8_8_8_REV) && !ctx->Pack.SwapBytes && _mesa_little_endian()) { memCopy = GL_TRUE; } else if ((texImage->TexFormat == MESA_FORMAT_AL88) && format == GL_LUMINANCE_ALPHA && type == GL_UNSIGNED_BYTE && !ctx->Pack.SwapBytes && _mesa_little_endian()) { memCopy = GL_TRUE; } else if ((texImage->TexFormat == MESA_FORMAT_L8) && format == GL_LUMINANCE && type == GL_UNSIGNED_BYTE) { memCopy = GL_TRUE; } else if (texImage->TexFormat == MESA_FORMAT_L16 && format == GL_LUMINANCE && type == GL_UNSIGNED_SHORT) { memCopy = GL_TRUE; } else if (texImage->TexFormat == MESA_FORMAT_A8 && format == GL_ALPHA && type == GL_UNSIGNED_BYTE) { memCopy = GL_TRUE; } else if (texImage->TexFormat == MESA_FORMAT_A16 && format == GL_ALPHA && type == GL_UNSIGNED_SHORT) { memCopy = GL_TRUE; } } if (memCopy) { const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat); const GLuint bytesPerRow = texImage->Width * bpp; GLubyte *dst = _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width, texImage->Height, format, type, 0, 0); const GLint dstRowStride = _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type); GLubyte *src; GLint srcRowStride; /* map src texture buffer */ ctx->Driver.MapTextureImage(ctx, texImage, 0, 0, 0, texImage->Width, texImage->Height, GL_MAP_READ_BIT, &src, &srcRowStride); if (src) { if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) { memcpy(dst, src, bytesPerRow * texImage->Height); } else { GLuint row; for (row = 0; row < texImage->Height; row++) { memcpy(dst, src, bytesPerRow); dst += dstRowStride; src += srcRowStride; } } /* unmap src texture buffer */ ctx->Driver.UnmapTextureImage(ctx, texImage, 0); } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); } } return memCopy; }