/** * 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; }
GLboolean _mesa_texstore_red_rgtc1(TEXSTORE_PARAMS) { GLubyte *dst; const GLubyte *tempImage = NULL; int i, j; int numxpixels, numypixels; const GLubyte *srcaddr; GLubyte srcpixels[4][4]; GLubyte *blkaddr; GLint dstRowDiff, redRowStride; GLubyte *tempImageSlices[1]; assert(dstFormat == MESA_FORMAT_R_RGTC1_UNORM || dstFormat == MESA_FORMAT_L_LATC1_UNORM); tempImage = malloc(srcWidth * srcHeight * 1 * sizeof(GLubyte)); if (!tempImage) return GL_FALSE; /* out of memory */ redRowStride = 1 * srcWidth * sizeof(GLubyte); tempImageSlices[0] = (GLubyte *) tempImage; _mesa_texstore(ctx, dims, baseInternalFormat, MESA_FORMAT_R_UNORM8, redRowStride, tempImageSlices, srcWidth, srcHeight, srcDepth, srcFormat, srcType, srcAddr, srcPacking); dst = dstSlices[0]; blkaddr = dst; dstRowDiff = dstRowStride >= (srcWidth * 2) ? dstRowStride - (((srcWidth + 3) & ~3) * 2) : 0; for (j = 0; j < srcHeight; j+=4) { if (srcHeight > j + 3) numypixels = 4; else numypixels = srcHeight - j; srcaddr = tempImage + j * srcWidth; for (i = 0; i < srcWidth; i += 4) { if (srcWidth > i + 3) numxpixels = 4; else numxpixels = srcWidth - i; extractsrc_u(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 1); util_format_unsigned_encode_rgtc_ubyte(blkaddr, srcpixels, numxpixels, numypixels); srcaddr += numxpixels; blkaddr += 8; } blkaddr += dstRowDiff; } free((void *) tempImage); return GL_TRUE; }
/** * 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); }
/** * Do a CopyTexSubImage operation using a read transfer from the source, * a write transfer to the destination and get_tile()/put_tile() to access * the pixels/texels. * * Note: srcY=0=TOP of renderbuffer */ static void fallback_copy_texsubimage(struct gl_context *ctx, struct st_renderbuffer *strb, struct st_texture_image *stImage, GLenum baseFormat, GLint destX, GLint destY, GLint destZ, GLint srcX, GLint srcY, GLsizei width, GLsizei height) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct pipe_transfer *src_trans; GLvoid *texDest; enum pipe_transfer_usage transfer_usage; void *map; if (ST_DEBUG & DEBUG_FALLBACK) debug_printf("%s: fallback processing\n", __FUNCTION__); if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { srcY = strb->Base.Height - srcY - height; } map = pipe_transfer_map(pipe, strb->texture, strb->rtt_level, strb->rtt_face + strb->rtt_slice, PIPE_TRANSFER_READ, srcX, srcY, width, height, &src_trans); if ((baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL) && util_format_is_depth_and_stencil(stImage->pt->format)) transfer_usage = PIPE_TRANSFER_READ_WRITE; else transfer_usage = PIPE_TRANSFER_WRITE; /* XXX this used to ignore destZ param */ texDest = st_texture_image_map(st, stImage, destZ, transfer_usage, destX, destY, width, height); if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL) { const GLboolean scaleOrBias = (ctx->Pixel.DepthScale != 1.0F || ctx->Pixel.DepthBias != 0.0F); GLint row, yStep; uint *data; /* determine bottom-to-top vs. top-to-bottom order for src buffer */ if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { srcY = height - 1; yStep = -1; } else { srcY = 0; yStep = 1; } data = malloc(width * sizeof(uint)); if (data) { /* To avoid a large temp memory allocation, do copy row by row */ for (row = 0; row < height; row++, srcY += yStep) { pipe_get_tile_z(src_trans, map, 0, srcY, width, 1, data); if (scaleOrBias) { _mesa_scale_and_bias_depth_uint(ctx, width, data); } pipe_put_tile_z(stImage->transfer, texDest, 0, row, width, 1, data); } } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage()"); } free(data); } else { /* RGBA format */ GLfloat *tempSrc = malloc(width * height * 4 * sizeof(GLfloat)); if (tempSrc && texDest) { const GLint dims = 2; const GLint dstRowStride = stImage->transfer->stride; struct gl_texture_image *texImage = &stImage->base; struct gl_pixelstore_attrib unpack = ctx->DefaultPacking; if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { unpack.Invert = GL_TRUE; } /* get float/RGBA image from framebuffer */ /* XXX this usually involves a lot of int/float conversion. * try to avoid that someday. */ pipe_get_tile_rgba_format(src_trans, map, 0, 0, width, height, util_format_linear(strb->texture->format), tempSrc); /* Store into texture memory. * Note that this does some special things such as pixel transfer * ops and format conversion. In particular, if the dest tex format * is actually RGBA but the user created the texture as GL_RGB we * need to fill-in/override the alpha channel with 1.0. */ _mesa_texstore(ctx, dims, texImage->_BaseFormat, texImage->TexFormat, dstRowStride, (GLubyte **) &texDest, width, height, 1, GL_RGBA, GL_FLOAT, tempSrc, /* src */ &unpack); } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage"); } free(tempSrc); } st_texture_image_unmap(st, stImage); pipe->transfer_unmap(pipe, src_trans); }
/** * Make texture containing an image for glDrawPixels image. * If 'pixels' is NULL, leave the texture image data undefined. */ static struct pipe_resource * make_texture(struct st_context *st, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) { struct gl_context *ctx = st->ctx; struct pipe_context *pipe = st->pipe; gl_format mformat; struct pipe_resource *pt; enum pipe_format pipeFormat; GLenum baseInternalFormat, intFormat; intFormat = internal_format(ctx, format, type); baseInternalFormat = _mesa_base_tex_format(ctx, intFormat); mformat = st_ChooseTextureFormat_renderable(ctx, intFormat, format, type, GL_FALSE); assert(mformat); pipeFormat = st_mesa_format_to_pipe_format(mformat); assert(pipeFormat); pixels = _mesa_map_pbo_source(ctx, unpack, pixels); if (!pixels) return NULL; /* alloc temporary texture */ pt = alloc_texture(st, width, height, pipeFormat); if (!pt) { _mesa_unmap_pbo_source(ctx, unpack); return NULL; } { struct pipe_transfer *transfer; static const GLuint dstImageOffsets = 0; GLboolean success; GLubyte *dest; const GLbitfield imageTransferStateSave = ctx->_ImageTransferState; /* we'll do pixel transfer in a fragment shader */ ctx->_ImageTransferState = 0x0; transfer = pipe_get_transfer(st->pipe, pt, 0, 0, PIPE_TRANSFER_WRITE, 0, 0, width, height); /* map texture transfer */ dest = pipe_transfer_map(pipe, transfer); /* Put image into texture transfer. * Note that the image is actually going to be upside down in * the texture. We deal with that with texcoords. */ success = _mesa_texstore(ctx, 2, /* dims */ baseInternalFormat, /* baseInternalFormat */ mformat, /* gl_format */ dest, /* dest */ 0, 0, 0, /* dstX/Y/Zoffset */ transfer->stride, /* dstRowStride, bytes */ &dstImageOffsets, /* dstImageOffsets */ width, height, 1, /* size */ format, type, /* src format/type */ pixels, /* data source */ unpack); /* unmap */ pipe_transfer_unmap(pipe, transfer); pipe->transfer_destroy(pipe, transfer); assert(success); /* restore */ ctx->_ImageTransferState = imageTransferStateSave; } _mesa_unmap_pbo_source(ctx, unpack); return pt; }
static bool intel_blit_texsubimage(struct gl_context * ctx, struct gl_texture_image *texImage, GLint xoffset, GLint yoffset, GLint width, GLint height, GLenum format, GLenum type, const void *pixels, const struct gl_pixelstore_attrib *packing) { struct intel_context *intel = intel_context(ctx); struct intel_texture_image *intelImage = intel_texture_image(texImage); /* Try to do a blit upload of the subimage if the texture is * currently busy. */ if (!intelImage->mt) return false; /* The blitter can't handle Y tiling */ if (intelImage->mt->region->tiling == I915_TILING_Y) return false; if (texImage->TexObject->Target != GL_TEXTURE_2D) return false; if (!drm_intel_bo_busy(intelImage->mt->region->bo)) return false; DBG("BLT subimage %s target %s level %d offset %d,%d %dx%d\n", __func__, _mesa_enum_to_string(texImage->TexObject->Target), texImage->Level, xoffset, yoffset, width, height); pixels = _mesa_validate_pbo_teximage(ctx, 2, width, height, 1, format, type, pixels, packing, "glTexSubImage"); if (!pixels) return false; struct intel_mipmap_tree *temp_mt = intel_miptree_create(intel, GL_TEXTURE_2D, texImage->TexFormat, 0, 0, width, height, 1, false, INTEL_MIPTREE_TILING_NONE); if (!temp_mt) goto err; GLubyte *dst = intel_miptree_map_raw(intel, temp_mt); if (!dst) goto err; if (!_mesa_texstore(ctx, 2, texImage->_BaseFormat, texImage->TexFormat, temp_mt->region->pitch, &dst, width, height, 1, format, type, pixels, packing)) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "intelTexSubImage"); } intel_miptree_unmap_raw(temp_mt); bool ret; ret = intel_miptree_blit(intel, temp_mt, 0, 0, 0, 0, false, intelImage->mt, texImage->Level, texImage->Face, xoffset, yoffset, false, width, height, COLOR_LOGICOP_COPY); assert(ret); intel_miptree_release(&temp_mt); _mesa_unmap_teximage_pbo(ctx, packing); return ret; err: _mesa_error(ctx, GL_OUT_OF_MEMORY, "intelTexSubImage"); intel_miptree_release(&temp_mt); _mesa_unmap_teximage_pbo(ctx, packing); return false; }
GLboolean _mesa_texstore_signed_rg_rgtc2(TEXSTORE_PARAMS) { GLbyte *dst; const GLfloat *tempImage = NULL; int i, j; int numxpixels, numypixels; const GLfloat *srcaddr; GLbyte srcpixels[4][4]; GLbyte *blkaddr; GLint dstRowDiff, rgRowStride; mesa_format tempFormat; GLfloat *tempImageSlices[1]; assert(dstFormat == MESA_FORMAT_RG_RGTC2_SNORM || dstFormat == MESA_FORMAT_LA_LATC2_SNORM); if (baseInternalFormat == GL_RG) tempFormat = MESA_FORMAT_RG_FLOAT32; else tempFormat = MESA_FORMAT_LA_FLOAT32; rgRowStride = 2 * srcWidth * sizeof(GLfloat); tempImage = malloc(srcWidth * srcHeight * 2 * sizeof(GLfloat)); if (!tempImage) return GL_FALSE; /* out of memory */ tempImageSlices[0] = (GLfloat *) tempImage; _mesa_texstore(ctx, dims, baseInternalFormat, tempFormat, rgRowStride, (GLubyte **)tempImageSlices, srcWidth, srcHeight, srcDepth, srcFormat, srcType, srcAddr, srcPacking); dst = (GLbyte *) dstSlices[0]; blkaddr = dst; dstRowDiff = dstRowStride >= (srcWidth * 4) ? dstRowStride - (((srcWidth + 3) & ~3) * 4) : 0; for (j = 0; j < srcHeight; j += 4) { if (srcHeight > j + 3) numypixels = 4; else numypixels = srcHeight - j; srcaddr = tempImage + j * srcWidth * 2; for (i = 0; i < srcWidth; i += 4) { if (srcWidth > i + 3) numxpixels = 4; else numxpixels = srcWidth - i; extractsrc_s(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 2); util_format_signed_encode_rgtc_ubyte(blkaddr, srcpixels, numxpixels, numypixels); blkaddr += 8; extractsrc_s(srcpixels, srcaddr + 1, srcWidth, numxpixels, numypixels, 2); util_format_signed_encode_rgtc_ubyte(blkaddr, srcpixels, numxpixels, numypixels); blkaddr += 8; srcaddr += numxpixels * 2; } blkaddr += dstRowDiff; } free((void *) tempImage); return GL_TRUE; }
/** * Helper function for storing 1D, 2D, 3D whole and subimages into texture * memory. * The source of the image data may be user memory or a PBO. In the later * case, we'll map the PBO, copy from it, then unmap it. */ static void store_texsubimage(struct gl_context *ctx, struct gl_texture_image *texImage, GLint xoffset, GLint yoffset, GLint zoffset, GLint width, GLint height, GLint depth, GLenum format, GLenum type, const GLvoid *pixels, const struct gl_pixelstore_attrib *packing, const char *caller) { const GLbitfield mapMode = get_read_write_mode(format, texImage->TexFormat); const GLenum target = texImage->TexObject->Target; GLboolean success = GL_FALSE; GLuint dims, slice, numSlices = 1, sliceOffset = 0; GLint srcImageStride = 0; const GLubyte *src; assert(xoffset + width <= texImage->Width); assert(yoffset + height <= texImage->Height); assert(zoffset + depth <= texImage->Depth); switch (target) { case GL_TEXTURE_1D: dims = 1; break; case GL_TEXTURE_2D_ARRAY: case GL_TEXTURE_CUBE_MAP_ARRAY: case GL_TEXTURE_3D: dims = 3; break; default: dims = 2; } /* get pointer to src pixels (may be in a pbo which we'll map here) */ src = (const GLubyte *) _mesa_validate_pbo_teximage(ctx, dims, width, height, depth, format, type, pixels, packing, caller); if (!src) return; /* compute slice info (and do some sanity checks) */ switch (target) { case GL_TEXTURE_2D: case GL_TEXTURE_RECTANGLE: case GL_TEXTURE_CUBE_MAP: case GL_TEXTURE_EXTERNAL_OES: /* one image slice, nothing special needs to be done */ break; case GL_TEXTURE_1D: assert(height == 1); assert(depth == 1); assert(yoffset == 0); assert(zoffset == 0); break; case GL_TEXTURE_1D_ARRAY: assert(depth == 1); assert(zoffset == 0); numSlices = height; sliceOffset = yoffset; height = 1; yoffset = 0; srcImageStride = _mesa_image_row_stride(packing, width, format, type); break; case GL_TEXTURE_2D_ARRAY: numSlices = depth; sliceOffset = zoffset; depth = 1; zoffset = 0; srcImageStride = _mesa_image_image_stride(packing, width, height, format, type); break; case GL_TEXTURE_3D: /* we'll store 3D images as a series of slices */ numSlices = depth; sliceOffset = zoffset; srcImageStride = _mesa_image_image_stride(packing, width, height, format, type); break; case GL_TEXTURE_CUBE_MAP_ARRAY: numSlices = depth; sliceOffset = zoffset; srcImageStride = _mesa_image_image_stride(packing, width, height, format, type); break; default: _mesa_warning(ctx, "Unexpected target 0x%x in store_texsubimage()", target); return; } assert(numSlices == 1 || srcImageStride != 0); for (slice = 0; slice < numSlices; slice++) { GLubyte *dstMap; GLint dstRowStride; ctx->Driver.MapTextureImage(ctx, texImage, slice + sliceOffset, xoffset, yoffset, width, height, mapMode, &dstMap, &dstRowStride); if (dstMap) { /* Note: we're only storing a 2D (or 1D) slice at a time but we need * to pass the right 'dims' value so that GL_UNPACK_SKIP_IMAGES is * used for 3D images. */ success = _mesa_texstore(ctx, dims, texImage->_BaseFormat, texImage->TexFormat, dstRowStride, &dstMap, width, height, 1, /* w, h, d */ format, type, src, packing); ctx->Driver.UnmapTextureImage(ctx, texImage, slice + sliceOffset); } src += srcImageStride; if (!success) break; } if (!success) _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller); _mesa_unmap_teximage_pbo(ctx, packing); }