#include "pipe/p_context.h"
#include "pipe/p_defines.h"
#include "pipe/p_inlines.h"
+#include "pipe/p_shader_tokens.h"
#include "util/u_tile.h"
#include "util/u_blit.h"
#include "util/u_surface.h"
+#include "util/u_math.h"
#define DBG if (0) printf
}
-static int
-logbase2(int n)
-{
- GLint i = 1, log2 = 0;
- while (n > i) {
- i *= 2;
- log2++;
- }
- return log2;
-}
-
-
/**
* Return default texture usage bitmask for the given texture format.
*/
* pagetable arrangements.
*/
if ((stObj->base.MinFilter == GL_NEAREST ||
- stObj->base.MinFilter == GL_LINEAR) &&
+ stObj->base.MinFilter == GL_LINEAR ||
+ stImage->base._BaseFormat == GL_DEPTH_COMPONENT ||
+ stImage->base._BaseFormat == GL_DEPTH_STENCIL_EXT) &&
stImage->level == firstLevel) {
lastLevel = firstLevel;
}
else {
- GLuint l2width = logbase2(width);
- GLuint l2height = logbase2(height);
- GLuint l2depth = logbase2(depth);
+ GLuint l2width = util_logbase2(width);
+ GLuint l2height = util_logbase2(height);
+ GLuint l2depth = util_logbase2(depth);
lastLevel = firstLevel + MAX2(MAX2(l2width, l2height), l2depth);
}
struct st_texture_image *stImage = st_texture_image(texImage);
GLint postConvWidth, postConvHeight;
GLint texelBytes, sizeInBytes;
- GLuint dstRowStride;
+ GLuint dstRowStride = 0;
struct gl_pixelstore_attrib unpackNB;
+ enum pipe_transfer_usage transfer_usage = 0;
DBG("%s target %s level %d %dx%dx%d border %d\n", __FUNCTION__,
_mesa_lookup_enum_by_nr(target), level, width, height, depth, border);
+ /* switch to "normal" */
+ if (stObj->surface_based) {
+ _mesa_clear_texture_object(ctx, texObj);
+ stObj->surface_based = GL_FALSE;
+ }
+
/* gallium does not support texture borders, strip it off */
if (border) {
strip_texture_border(border, &width, &height, &depth, unpack, &unpackNB);
format, type,
pixels, unpack, "glTexImage");
}
- if (!pixels)
- return;
+
+ /* Note: we can't check for pixels==NULL until after we've allocated
+ * memory for the texture.
+ */
/* See if we can do texture compression with a blit/render.
*/
stImage->pt->format,
stImage->pt->target,
PIPE_TEXTURE_USAGE_RENDER_TARGET, 0)) {
+ if (!pixels)
+ goto done;
+
if (compress_with_blit(ctx, target, level, 0, 0, 0, width, height, depth,
format, type, pixels, unpack, texImage)) {
- return;
+ goto done;
}
}
if (stImage->pt) {
+ if (format == GL_DEPTH_COMPONENT &&
+ pf_is_depth_and_stencil(stImage->pt->format))
+ transfer_usage = PIPE_TRANSFER_READ_WRITE;
+ else
+ transfer_usage = PIPE_TRANSFER_WRITE;
+
texImage->Data = st_texture_image_map(ctx->st, stImage, 0,
- PIPE_TRANSFER_WRITE, 0, 0,
+ transfer_usage, 0, 0,
stImage->base.Width,
stImage->base.Height);
if(stImage->transfer)
return;
}
+ if (!pixels)
+ goto done;
+
DBG("Upload image %dx%dx%d row_len %x pitch %x\n",
width, height, depth, width * texelBytes, dstRowStride);
st_texture_image_unmap(ctx->st, stImage);
/* map next slice of 3D texture */
texImage->Data = st_texture_image_map(ctx->st, stImage, i + 1,
- PIPE_TRANSFER_WRITE, 0, 0,
+ transfer_usage, 0, 0,
stImage->base.Width,
stImage->base.Height);
src += srcImageStride;
}
}
+done:
_mesa_unmap_teximage_pbo(ctx, unpack);
if (stImage->pt && texImage->Data) {
st_texture_image_unmap(ctx->st, stImage);
texImage->Data = NULL;
}
-
- if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
- ctx->Driver.GenerateMipmap(ctx, target, texObj);
- }
}
PIPE_TRANSFER_READ,
0, 0, width, height);
- pixels = _mesa_map_readpix_pbo(ctx, &ctx->Pack, pixels);
+ pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels);
/* copy/pack data into user buffer */
if (st_equal_formats(stImage->pt->format, format, type)) {
}
}
- _mesa_unmap_readpix_pbo(ctx, &ctx->Pack);
+ _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
/* destroy the temp / dest surface */
util_destroy_rgba_surface(dst_texture, dst_surface);
/* Image is stored in hardware format in a buffer managed by the
* kernel. Need to explicitly map and unmap it.
*/
+ unsigned face = _mesa_tex_target_to_face(target);
- st_teximage_flush_before_map(ctx->st, stImage->pt, 0, level,
+ st_teximage_flush_before_map(ctx->st, stImage->pt, face, level,
PIPE_TRANSFER_READ);
texImage->Data = st_texture_image_map(ctx->st, stImage, 0,
_mesa_image_image_stride(packing, width, height, format, type);
GLint i;
const GLubyte *src;
+ /* init to silence warning only: */
+ enum pipe_transfer_usage transfer_usage = PIPE_TRANSFER_WRITE;
DBG("%s target %s level %d offset %d,%d %dx%d\n", __FUNCTION__,
_mesa_lookup_enum_by_nr(target),
xoffset, yoffset, zoffset,
width, height, depth,
format, type, pixels, packing, texImage)) {
- return;
+ goto done;
}
}
* from uploading the buffer under us.
*/
if (stImage->pt) {
- st_teximage_flush_before_map(ctx->st, stImage->pt, 0, level,
- PIPE_TRANSFER_WRITE);
+ unsigned face = _mesa_tex_target_to_face(target);
+
+ if (format == GL_DEPTH_COMPONENT &&
+ pf_is_depth_and_stencil(stImage->pt->format))
+ transfer_usage = PIPE_TRANSFER_READ_WRITE;
+ else
+ transfer_usage = PIPE_TRANSFER_WRITE;
+
+ st_teximage_flush_before_map(ctx->st, stImage->pt, face, level,
+ transfer_usage);
texImage->Data = st_texture_image_map(ctx->st, stImage, zoffset,
- PIPE_TRANSFER_WRITE,
+ transfer_usage,
xoffset, yoffset,
width, height);
}
if (!texImage->Data) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage");
- return;
+ goto done;
}
src = (const GLubyte *) pixels;
/* map next slice of 3D texture */
texImage->Data = st_texture_image_map(ctx->st, stImage,
zoffset + i + 1,
- PIPE_TRANSFER_WRITE,
+ transfer_usage,
xoffset, yoffset,
width, height);
src += srcImageStride;
}
}
- if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
- ctx->Driver.GenerateMipmap(ctx, target, texObj);
- }
-
+done:
_mesa_unmap_teximage_pbo(ctx, packing);
if (stImage->pt) {
}
+static void
+st_CompressedTexSubImage1D(GLcontext *ctx, GLenum target, GLint level,
+ GLint xoffset, GLsizei width,
+ GLenum format,
+ GLsizei imageSize, const GLvoid *data,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ assert(0);
+}
+
+
+static void
+st_CompressedTexSubImage2D(GLcontext *ctx, GLenum target, GLint level,
+ GLint xoffset, GLint yoffset,
+ GLsizei width, GLint height,
+ GLenum format,
+ GLsizei imageSize, const GLvoid *data,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ struct st_texture_image *stImage = st_texture_image(texImage);
+ struct pipe_format_block block;
+ int srcBlockStride;
+ int dstBlockStride;
+ int y;
+
+ if (stImage->pt) {
+ unsigned face = _mesa_tex_target_to_face(target);
+
+ st_teximage_flush_before_map(ctx->st, stImage->pt, face, level,
+ PIPE_TRANSFER_WRITE);
+ texImage->Data = st_texture_image_map(ctx->st, stImage, 0,
+ PIPE_TRANSFER_WRITE,
+ xoffset, yoffset,
+ width, height);
+
+ block = stImage->pt->block;
+ srcBlockStride = pf_get_stride(&block, width);
+ dstBlockStride = stImage->transfer->stride;
+ } else {
+ assert(stImage->pt);
+ /* TODO find good values for block and strides */
+ /* TODO also adjust texImage->data for yoffset/xoffset */
+ return;
+ }
+
+ if (!texImage->Data) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexSubImage");
+ return;
+ }
+
+ assert(xoffset % block.width == 0);
+ assert(yoffset % block.height == 0);
+ assert(width % block.width == 0);
+ assert(height % block.height == 0);
+
+ for (y = 0; y < height; y += block.height) {
+ /* don't need to adjust for xoffset and yoffset as st_texture_image_map does that */
+ const char *src = (const char*)data + srcBlockStride * pf_get_nblocksy(&block, y);
+ char *dst = (char*)texImage->Data + dstBlockStride * pf_get_nblocksy(&block, y);
+ memcpy(dst, src, pf_get_stride(&block, width));
+ }
+
+ if (stImage->pt) {
+ st_texture_image_unmap(ctx->st, stImage);
+ texImage->Data = NULL;
+ }
+}
+
+
+static void
+st_CompressedTexSubImage3D(GLcontext *ctx, GLenum target, GLint level,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLint height, GLint depth,
+ GLenum format,
+ GLsizei imageSize, const GLvoid *data,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ assert(0);
+}
+
+
/**
* Do a CopyTexSubImage operation using a read transfer from the source,
struct pipe_screen *screen = pipe->screen;
struct pipe_transfer *src_trans;
GLvoid *texDest;
+ enum pipe_transfer_usage transfer_usage;
assert(width <= MAX_WIDTH);
srcX, srcY,
width, height);
+ if (baseFormat == GL_DEPTH_COMPONENT &&
+ pf_is_depth_and_stencil(stImage->pt->format))
+ transfer_usage = PIPE_TRANSFER_READ_WRITE;
+ else
+ transfer_usage = PIPE_TRANSFER_WRITE;
+
st_teximage_flush_before_map(ctx->st, stImage->pt, 0, 0,
- PIPE_TRANSFER_WRITE);
+ transfer_usage);
- texDest = st_texture_image_map(ctx->st, stImage, 0, PIPE_TRANSFER_WRITE,
+ texDest = st_texture_image_map(ctx->st, stImage, 0, transfer_usage,
destX, destY, width, height);
if (baseFormat == GL_DEPTH_COMPONENT ||
}
+static unsigned
+compatible_src_dst_formats(const struct gl_renderbuffer *src,
+ const struct gl_texture_image *dst)
+{
+ const GLenum srcFormat = src->_BaseFormat;
+ const GLenum dstLogicalFormat = dst->_BaseFormat;
+
+ if (srcFormat == dstLogicalFormat) {
+ /* This is the same as matching_base_formats, which should
+ * always pass, as it did previously.
+ */
+ return TGSI_WRITEMASK_XYZW;
+ }
+ else if (srcFormat == GL_RGBA &&
+ dstLogicalFormat == GL_RGB) {
+ /* Add a single special case to cope with RGBA->RGB transfers,
+ * setting A to 1.0 to cope with situations where the RGB
+ * destination is actually stored as RGBA.
+ */
+ return TGSI_WRITEMASK_XYZ; /* A ==> 1.0 */
+ }
+ else {
+ /* Otherwise fail.
+ */
+ return 0;
+ }
+}
+
+
+
/**
* Do a CopyTex[Sub]Image1/2/3D() using a hardware (blit) path if possible.
* Note that the region to copy has already been clipped so we know we
enum pipe_format dest_format, src_format;
GLboolean use_fallback = GL_TRUE;
GLboolean matching_base_formats;
+ GLuint format_writemask;
+ struct pipe_surface *dest_surface = NULL;
+ GLboolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP);
+
+ /* any rendering in progress must flushed before we grab the fb image */
+ st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
/* make sure finalize_textures has been called?
*/
return;
}
+ if (srcX < 0) {
+ width -= -srcX;
+ destX += -srcX;
+ srcX = 0;
+ }
+
+ if (srcY < 0) {
+ height -= -srcY;
+ destY += -srcY;
+ srcY = 0;
+ }
+
+ if (destX < 0) {
+ width -= -destX;
+ srcX += -destX;
+ destX = 0;
+ }
+
+ if (destY < 0) {
+ height -= -destY;
+ srcY += -destY;
+ destY = 0;
+ }
+
+ if (width < 0 || height < 0)
+ return;
+
+
assert(strb);
assert(strb->surface);
assert(stImage->pt);
* textured-quad paths.
*/
matching_base_formats = (strb->Base._BaseFormat == texImage->_BaseFormat);
+ format_writemask = compatible_src_dst_formats(&strb->Base, texImage);
- if (matching_base_formats && ctx->_ImageTransferState == 0x0) {
- /* try potential hardware path */
- struct pipe_surface *dest_surface = NULL;
- boolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP);
+ if (ctx->_ImageTransferState == 0x0) {
- if (src_format == dest_format && !do_flip) {
+ if (matching_base_formats &&
+ src_format == dest_format &&
+ !do_flip)
+ {
/* use surface_copy() / blit */
dest_surface = screen->get_tex_surface(screen, stImage->pt,
width, height);
use_fallback = GL_FALSE;
}
- else if (screen->is_format_supported(screen, src_format,
+ else if (format_writemask &&
+ screen->is_format_supported(screen, src_format,
PIPE_TEXTURE_2D,
PIPE_TEXTURE_USAGE_SAMPLER,
0) &&
srcY0 = srcY;
srcY1 = srcY0 + height;
}
- util_blit_pixels(ctx->st->blit,
- strb->surface,
- srcX, srcY0,
- srcX + width, srcY1,
- dest_surface,
- destX, destY,
- destX + width, destY + height,
- 0.0, PIPE_TEX_MIPFILTER_NEAREST);
+ util_blit_pixels_writemask(ctx->st->blit,
+ strb->surface,
+ srcX, srcY0,
+ srcX + width, srcY1,
+ dest_surface,
+ destX, destY,
+ destX + width, destY + height,
+ 0.0, PIPE_TEX_MIPFILTER_NEAREST,
+ format_writemask);
use_fallback = GL_FALSE;
}
destX, destY, destZ,
srcX, srcY, width, height);
}
-
- if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
- ctx->Driver.GenerateMipmap(ctx, target, texObj);
- }
}
functions->TexSubImage1D = st_TexSubImage1D;
functions->TexSubImage2D = st_TexSubImage2D;
functions->TexSubImage3D = st_TexSubImage3D;
+ functions->CompressedTexSubImage1D = st_CompressedTexSubImage1D;
+ functions->CompressedTexSubImage2D = st_CompressedTexSubImage2D;
+ functions->CompressedTexSubImage3D = st_CompressedTexSubImage3D;
functions->CopyTexImage1D = st_CopyTexImage1D;
functions->CopyTexImage2D = st_CopyTexImage2D;
functions->CopyTexSubImage1D = st_CopyTexSubImage1D;