/** * This is the software fallback for Driver.GetCompressedTexImage(). * All error checking will have been done before this routine is called. */ void _mesa_get_compressed_teximage(GLcontext *ctx, GLenum target, GLint level, GLvoid *img, struct gl_texture_object *texObj, struct gl_texture_image *texImage) { const GLuint row_stride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width); const GLuint row_stride_stored = _mesa_format_row_stride(texImage->TexFormat, texImage->RowStride); GLuint i; if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { /* pack texture image into a PBO */ GLubyte *buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj); if (!buf) { /* out of memory or other unexpected error */ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetCompresssedTexImage(map PBO failed)"); return; } img = ADD_POINTERS(buf, img); } /* no pixelstore or pixel transfer, but respect stride */ if (row_stride == row_stride_stored) { const GLuint size = _mesa_format_image_size(texImage->TexFormat, texImage->Width, texImage->Height, texImage->Depth); _mesa_memcpy(img, texImage->Data, size); } else { GLuint bw, bh; _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh); for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) { memcpy((GLubyte *)img + i * row_stride, (GLubyte *)texImage->Data + i * row_stride_stored, row_stride); } } if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, ctx->Pack.BufferObj); } }
/** * This is the software fallback for Driver.GetCompressedTexImage(). * All error checking will have been done before this routine is called. */ void _mesa_get_compressed_teximage(struct gl_context *ctx, struct gl_texture_image *texImage, GLvoid *img) { const GLuint row_stride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width); GLuint i; GLubyte *src; GLint srcRowStride; if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { /* pack texture image into a PBO */ GLubyte *buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size, GL_MAP_WRITE_BIT, ctx->Pack.BufferObj); if (!buf) { /* out of memory or other unexpected error */ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetCompresssedTexImage(map PBO failed)"); return; } img = ADD_POINTERS(buf, img); } /* map src texture buffer */ ctx->Driver.MapTextureImage(ctx, texImage, 0, 0, 0, texImage->Width, texImage->Height, GL_MAP_READ_BIT, &src, &srcRowStride); if (src) { /* no pixelstore or pixel transfer, but respect stride */ if (row_stride == srcRowStride) { const GLuint size = _mesa_format_image_size(texImage->TexFormat, texImage->Width, texImage->Height, texImage->Depth); memcpy(img, src, size); } else { GLuint bw, bh; _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh); for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) { memcpy((GLubyte *)img + i * row_stride, (GLubyte *)src + i * srcRowStride, row_stride); } } ctx->Driver.UnmapTextureImage(ctx, texImage, 0); } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetCompresssedTexImage"); } if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj); } }
/** * Map texture memory/buffer into user space. * Note: the region of interest parameters are ignored here. * \param mapOut returns start of mapping of region of interest * \param rowStrideOut returns row stride in bytes */ static void radeon_map_texture_image(struct gl_context *ctx, struct gl_texture_image *texImage, GLuint slice, GLuint x, GLuint y, GLuint w, GLuint h, GLbitfield mode, GLubyte **map, GLint *stride) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); radeon_texture_image *image = get_radeon_texture_image(texImage); radeon_mipmap_tree *mt = image->mt; GLuint texel_size = _mesa_get_format_bytes(texImage->TexFormat); GLuint width = texImage->Width; GLuint height = texImage->Height; struct radeon_bo *bo = !image->mt ? image->bo : image->mt->bo; unsigned int bw, bh; GLboolean write = (mode & GL_MAP_WRITE_BIT) != 0; _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh); assert(y % bh == 0); y /= bh; texel_size /= bw; if (bo && radeon_bo_is_referenced_by_cs(bo, rmesa->cmdbuf.cs)) { radeon_print(RADEON_TEXTURE, RADEON_VERBOSE, "%s for texture that is " "queued for GPU processing.\n", __func__); radeon_firevertices(rmesa); } if (image->bo) { /* TFP case */ radeon_bo_map(image->bo, write); *stride = get_texture_image_row_stride(rmesa, texImage->TexFormat, width, 0, texImage->TexObject->Target); *map = bo->ptr; } else if (likely(mt)) { void *base; radeon_mipmap_level *lvl = &image->mt->levels[texImage->Level]; radeon_bo_map(mt->bo, write); base = mt->bo->ptr + lvl->faces[image->base.Base.Face].offset; *stride = lvl->rowstride; *map = base + (slice * height) * *stride; } else { /* texture data is in malloc'd memory */ assert(map); *stride = _mesa_format_row_stride(texImage->TexFormat, width); *map = image->base.Buffer + (slice * height) * *stride; } *map += y * *stride + x * texel_size; }
/** * Compute compressed_pixelstore parameters for copying compressed * texture data. * \param dims number of texture image dimensions: 1, 2 or 3 * \param texFormat the compressed texture format * \param width, height, depth size of image to copy * \param packing pixelstore parameters describing user-space image packing * \param store returns the compressed_pixelstore parameters */ void _mesa_compute_compressed_pixelstore(GLuint dims, mesa_format texFormat, GLsizei width, GLsizei height, GLsizei depth, const struct gl_pixelstore_attrib *packing, struct compressed_pixelstore *store) { GLuint bw, bh; _mesa_get_format_block_size(texFormat, &bw, &bh); store->SkipBytes = 0; store->TotalBytesPerRow = store->CopyBytesPerRow = _mesa_format_row_stride(texFormat, width); store->TotalRowsPerSlice = store->CopyRowsPerSlice = (height + bh - 1) / bh; store->CopySlices = depth; if (packing->CompressedBlockWidth && packing->CompressedBlockSize) { bw = packing->CompressedBlockWidth; if (packing->RowLength) { store->TotalBytesPerRow = packing->CompressedBlockSize * ((packing->RowLength + bw - 1) / bw); } store->SkipBytes += packing->SkipPixels * packing->CompressedBlockSize / bw; } if (dims > 1 && packing->CompressedBlockHeight && packing->CompressedBlockSize) { bh = packing->CompressedBlockHeight; store->SkipBytes += packing->SkipRows * store->TotalBytesPerRow / bh; store->CopyRowsPerSlice = (height + bh - 1) / bh; /* rows in blocks */ if (packing->ImageHeight) { store->TotalRowsPerSlice = (packing->ImageHeight + bh - 1) / bh; } } if (dims > 2 && packing->CompressedBlockDepth && packing->CompressedBlockSize) { int bd = packing->CompressedBlockDepth; store->SkipBytes += packing->SkipImages * store->TotalBytesPerRow * store->TotalRowsPerSlice / bd; } }
unsigned get_texture_image_row_stride(radeonContextPtr rmesa, mesa_format format, unsigned width, unsigned tiling, GLuint target) { if (_mesa_is_format_compressed(format)) { return get_aligned_compressed_row_stride(format, width, rmesa->texture_compressed_row_align); } else { unsigned row_align; if (!_mesa_is_pow_two(width) || target == GL_TEXTURE_RECTANGLE) { row_align = rmesa->texture_rect_row_align - 1; } else if (tiling) { unsigned tileWidth, tileHeight; get_tile_size(format, &tileWidth, &tileHeight); row_align = tileWidth * _mesa_get_format_bytes(format) - 1; } else { row_align = rmesa->texture_row_align - 1; } return (_mesa_format_row_stride(format, width) + row_align) & ~row_align; } }
/** * Map a 2D slice of a texture image into user space. * (x,y,w,h) defines a region of interest (ROI). Reading/writing texels * outside of the ROI is undefined. * * \param texImage the texture image * \param slice the 3D image slice or array texture slice * \param x, y, w, h region of interest * \param mode bitmask of GL_MAP_READ_BIT, GL_MAP_WRITE_BIT * \param mapOut returns start of mapping of region of interest * \param rowStrideOut returns row stride (in bytes) */ void _swrast_map_teximage(struct gl_context *ctx, struct gl_texture_image *texImage, GLuint slice, GLuint x, GLuint y, GLuint w, GLuint h, GLbitfield mode, GLubyte **mapOut, GLint *rowStrideOut) { struct swrast_texture_image *swImage = swrast_texture_image(texImage); GLubyte *map; GLint stride, texelSize; GLuint bw, bh; _mesa_check_map_teximage(texImage, slice, x, y, w, h); texelSize = _mesa_get_format_bytes(texImage->TexFormat); stride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width); _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh); assert(x % bw == 0); assert(y % bh == 0); if (!swImage->Buffer) { /* probably ran out of memory when allocating tex mem */ *mapOut = NULL; return; } map = swImage->Buffer; /* apply x/y offset to map address */ map += stride * (y / bh) + texelSize * (x / bw); *mapOut = map; *rowStrideOut = stride; }
/** * Update a subregion of the given texture image. */ static void radeon_store_teximage(GLcontext* ctx, int dims, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, GLenum format, GLenum type, const GLvoid * pixels, const struct gl_pixelstore_attrib *packing, struct gl_texture_object *texObj, struct gl_texture_image *texImage, int compressed) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); radeonTexObj *t = radeon_tex_obj(texObj); radeon_texture_image* image = get_radeon_texture_image(texImage); GLuint dstRowStride; GLuint *dstImageOffsets; radeon_print(RADEON_TEXTURE, RADEON_TRACE, "%s(%p, tex %p, image %p) compressed %d\n", __func__, ctx, texObj, texImage, compressed); if (image->mt) { dstRowStride = image->mt->levels[image->mtlevel].rowstride; } else if (t->bo) { /* TFP case */ dstRowStride = get_texture_image_row_stride(rmesa, texImage->TexFormat, width, 0); } else { dstRowStride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width); } assert(dstRowStride); if (dims == 3) { unsigned alignedWidth = dstRowStride/_mesa_get_format_bytes(texImage->TexFormat); dstImageOffsets = allocate_image_offsets(ctx, alignedWidth, texImage->Height, texImage->Depth); if (!dstImageOffsets) { radeon_warning("%s Failed to allocate dstImaeOffset.\n", __func__); return; } } else { dstImageOffsets = texImage->ImageOffsets; } radeon_teximage_map(image, GL_TRUE); if (compressed) { uint32_t srcRowStride, bytesPerRow, rows, block_width, block_height; GLubyte *img_start; _mesa_get_format_block_size(texImage->TexFormat, &block_width, &block_height); if (!image->mt) { dstRowStride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width); img_start = _mesa_compressed_image_address(xoffset, yoffset, 0, texImage->TexFormat, texImage->Width, texImage->Data); } else { uint32_t offset; offset = dstRowStride / _mesa_get_format_bytes(texImage->TexFormat) * yoffset / block_height + xoffset / block_width; offset *= _mesa_get_format_bytes(texImage->TexFormat); img_start = texImage->Data + offset; } srcRowStride = _mesa_format_row_stride(texImage->TexFormat, width); bytesPerRow = srcRowStride; rows = (height + block_height - 1) / block_height; copy_rows(img_start, dstRowStride, pixels, srcRowStride, rows, bytesPerRow); } else { if (!_mesa_texstore(ctx, dims, texImage->_BaseFormat, texImage->TexFormat, texImage->Data, xoffset, yoffset, zoffset, dstRowStride, dstImageOffsets, width, height, depth, format, type, pixels, packing)) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage"); } } if (dims == 3) { free(dstImageOffsets); } radeon_teximage_unmap(image); }
/** * Called via ctx->Driver.MapRenderbuffer. */ static void st_MapRenderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint x, GLuint y, GLuint w, GLuint h, GLbitfield mode, GLubyte **mapOut, GLint *rowStrideOut) { struct st_context *st = st_context(ctx); struct st_renderbuffer *strb = st_renderbuffer(rb); struct pipe_context *pipe = st->pipe; const GLboolean invert = rb->Name == 0; unsigned usage; GLuint y2; GLubyte *map; if (strb->software) { /* software-allocated renderbuffer (probably an accum buffer) */ if (strb->data) { GLint bpp = _mesa_get_format_bytes(strb->Base.Format); GLint stride = _mesa_format_row_stride(strb->Base.Format, strb->Base.Width); *mapOut = (GLubyte *) strb->data + y * stride + x * bpp; *rowStrideOut = stride; } else { *mapOut = NULL; *rowStrideOut = 0; } return; } usage = 0x0; if (mode & GL_MAP_READ_BIT) usage |= PIPE_TRANSFER_READ; if (mode & GL_MAP_WRITE_BIT) usage |= PIPE_TRANSFER_WRITE; if (mode & GL_MAP_INVALIDATE_RANGE_BIT) usage |= PIPE_TRANSFER_DISCARD_RANGE; /* Note: y=0=bottom of buffer while y2=0=top of buffer. * 'invert' will be true for window-system buffers and false for * user-allocated renderbuffers and textures. */ if (invert) y2 = strb->Base.Height - y - h; else y2 = y; map = pipe_transfer_map(pipe, strb->texture, strb->surface->u.tex.level, strb->surface->u.tex.first_layer, usage, x, y2, w, h, &strb->transfer); if (map) { if (invert) { *rowStrideOut = -(int) strb->transfer->stride; map += (h - 1) * strb->transfer->stride; } else { *rowStrideOut = strb->transfer->stride; } *mapOut = map; } else { *mapOut = NULL; *rowStrideOut = 0; } }
/** * Called via ctx->Driver.MapRenderbuffer() */ void xmesa_MapRenderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint x, GLuint y, GLuint w, GLuint h, GLbitfield mode, GLubyte **mapOut, GLint *rowStrideOut) { struct xmesa_renderbuffer *xrb = xmesa_renderbuffer(rb); if (xrb->Base.Base.ClassID == XMESA_RENDERBUFFER) { XImage *ximage = xrb->ximage; assert(!xrb->map_mode); /* only a single mapping allowed */ xrb->map_mode = mode; xrb->map_x = x; xrb->map_y = y; xrb->map_w = w; xrb->map_h = h; if (ximage) { int y2 = rb->Height - y - 1; *mapOut = (GLubyte *) ximage->data + y2 * ximage->bytes_per_line + x * ximage->bits_per_pixel / 8; } else { /* this must be a pixmap/window renderbuffer */ int (*old_handler)(XMesaDisplay *, XErrorEvent *); int y2 = rb->Height - y - h; assert(xrb->pixmap); /* Install error handler for XGetImage() in case the the window * isn't mapped. If we fail we'll create a temporary XImage. */ mesaXErrorFlag = 0; old_handler = XSetErrorHandler(mesaHandleXError); /* read pixel data out of the pixmap/window into an XImage */ ximage = XGetImage(xrb->Parent->display, xrb->pixmap, x, y2, w, h, AllPlanes, ZPixmap); XSetErrorHandler(old_handler); if (mesaXErrorFlag) { /* create new, temporary XImage */ int bytes_per_line = _mesa_format_row_stride(xrb->Base.Base.Format, xrb->Base.Base.Width); char *image = (char *) malloc(bytes_per_line * xrb->Base.Base.Height); ximage = XCreateImage(xrb->Parent->display, xrb->Parent->xm_visual->visinfo->visual, xrb->Parent->xm_visual->visinfo->depth, ZPixmap, /* format */ 0, /* offset */ image, /* data */ xrb->Base.Base.Width, xrb->Base.Base.Height, 8, /* pad */ bytes_per_line); } if (!ximage) { *mapOut = NULL; *rowStrideOut = 0; return; } xrb->map_ximage = ximage; /* the first row of the OpenGL image is last row of the XImage */ *mapOut = (GLubyte *) ximage->data + (h - 1) * ximage->bytes_per_line; } /* We return a negative stride here since XImage data is upside down * with respect to OpenGL images. */ *rowStrideOut = -ximage->bytes_per_line; return; } /* otherwise, this is an ordinary malloc-based renderbuffer */ _swrast_map_soft_renderbuffer(ctx, rb, x, y, w, h, mode, mapOut, rowStrideOut); }