diff options
Diffstat (limited to 'src/mesa/state_tracker/st_cb_texture.c')
-rw-r--r-- | src/mesa/state_tracker/st_cb_texture.c | 283 |
1 files changed, 169 insertions, 114 deletions
diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c index ed113b5dbc..7e2e533881 100644 --- a/src/mesa/state_tracker/st_cb_texture.c +++ b/src/mesa/state_tracker/st_cb_texture.c @@ -120,17 +120,18 @@ static void st_DeleteTextureObject(GLcontext *ctx, struct gl_texture_object *texObj) { + struct st_context *st = st_context(ctx); struct st_texture_object *stObj = st_texture_object(texObj); if (stObj->pt) pipe_resource_reference(&stObj->pt, NULL); if (stObj->sampler_view) { - if (stObj->sampler_view->context != ctx->st->pipe) { + if (stObj->sampler_view->context != st->pipe) { /* Take "ownership" of this texture sampler view by setting * its context pointer to this context. This avoids potential * crashes when the texture object is shared among contexts * and the original/owner context has already been destroyed. */ - stObj->sampler_view->context = ctx->st->pipe; + stObj->sampler_view->context = st->pipe; } pipe_sampler_view_reference(&stObj->sampler_view, NULL); } @@ -208,84 +209,108 @@ do_memcpy(void *dest, const void *src, size_t n) /** - * Return default texture usage bitmask for the given texture format. + * Return default texture resource binding bitmask for the given format. */ static GLuint -default_usage(enum pipe_format fmt) +default_bindings(struct st_context *st, enum pipe_format format) { - GLuint usage = PIPE_BIND_SAMPLER_VIEW; - if (util_format_is_depth_or_stencil(fmt)) - usage |= PIPE_BIND_DEPTH_STENCIL; + struct pipe_screen *screen = st->pipe->screen; + const unsigned target = PIPE_TEXTURE_2D; + const unsigned geom = 0x0; + unsigned bindings; + + if (util_format_is_depth_or_stencil(format)) + bindings = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_DEPTH_STENCIL; + else + bindings = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; + + if (screen->is_format_supported(screen, format, target, bindings, geom)) + return bindings; else - usage |= PIPE_BIND_RENDER_TARGET; - return usage; + return PIPE_BIND_SAMPLER_VIEW; +} + + +/** Return number of image dimensions (1, 2 or 3) for a texture target. */ +static GLuint +get_texture_dims(GLenum target) +{ + switch (target) { + case GL_TEXTURE_1D: + case GL_TEXTURE_1D_ARRAY_EXT: + return 1; + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP_ARB: + case GL_TEXTURE_RECTANGLE_NV: + case GL_TEXTURE_2D_ARRAY_EXT: + return 2; + case GL_TEXTURE_3D: + return 3; + default: + assert(0 && "invalid texture target in get_texture_dims()"); + return 1; + } } /** - * Allocate a pipe_resource object for the given st_texture_object using - * the given st_texture_image to guess the mipmap size/levels. + * Try to allocate a pipe_resource object for the given st_texture_object. * - * [comments...] - * Otherwise, store it in memory if (Border != 0) or (any dimension == - * 1). - * - * Otherwise, if max_level >= level >= min_level, create texture with - * space for images from min_level down to max_level. + * We use the given st_texture_image as a clue to determine the size of the + * mipmap image at level=0. * - * Otherwise, create texture with space for images from (level 0)..(1x1). - * Consider pruning this texture at a validation if the saving is worth it. */ static void guess_and_alloc_texture(struct st_context *st, struct st_texture_object *stObj, const struct st_texture_image *stImage) { - GLuint firstLevel; - GLuint lastLevel; - GLuint width = stImage->base.Width2; /* size w/out border */ - GLuint height = stImage->base.Height2; - GLuint depth = stImage->base.Depth2; - GLuint i, usage; + const GLuint dims = get_texture_dims(stObj->base.Target); + GLuint level, lastLevel, width, height, depth; + GLuint bindings; enum pipe_format fmt; DBG("%s\n", __FUNCTION__); assert(!stObj->pt); - if (stObj->pt && - (GLint) stImage->level > stObj->base.BaseLevel && - (stImage->base.Width == 1 || - (stObj->base.Target != GL_TEXTURE_1D && - stImage->base.Height == 1) || - (stObj->base.Target == GL_TEXTURE_3D && - stImage->base.Depth == 1))) - return; - - /* If this image disrespects BaseLevel, allocate from level zero. - * Usually BaseLevel == 0, so it's unlikely to happen. - */ - if ((GLint) stImage->level < stObj->base.BaseLevel) - firstLevel = 0; - else - firstLevel = stObj->base.BaseLevel; + level = stImage->level; + width = stImage->base.Width2; /* size w/out border */ + height = stImage->base.Height2; + depth = stImage->base.Depth2; + assert(width > 0); + assert(height > 0); + assert(depth > 0); - /* Figure out image dimensions at start level. + /* Depending on the image's size, we can't always make a guess here. */ - for (i = stImage->level; i > firstLevel; i--) { + if (level > 0) { + if ( (dims >= 1 && width == 1) || + (dims >= 2 && height == 1) || + (dims >= 3 && depth == 1) ) { + /* we can't determine the image size at level=0 */ + stObj->width0 = stObj->height0 = stObj->depth0 = 0; + return; + } + } + + /* grow the image size until we hit level = 0 */ + while (level > 0) { if (width != 1) width <<= 1; if (height != 1) height <<= 1; if (depth != 1) depth <<= 1; - } + level--; + } - if (width == 0 || height == 0 || depth == 0) { - /* no texture needed */ - return; - } + assert(level == 0); + + /* At this point, (width x height x depth) is the expected size of + * the level=0 mipmap image. + */ /* Guess a reasonable value for lastLevel. This is probably going * to be wrong fairly often and might mean that we have to look at @@ -297,21 +322,26 @@ guess_and_alloc_texture(struct st_context *st, stImage->base._BaseFormat == GL_DEPTH_COMPONENT || stImage->base._BaseFormat == GL_DEPTH_STENCIL_EXT) && !stObj->base.GenerateMipmap && - stImage->level == firstLevel) { + stImage->level == 0) { /* only alloc space for a single mipmap level */ - lastLevel = firstLevel; + lastLevel = 0; } else { /* alloc space for a full mipmap */ GLuint l2width = util_logbase2(width); GLuint l2height = util_logbase2(height); GLuint l2depth = util_logbase2(depth); - lastLevel = firstLevel + MAX2(MAX2(l2width, l2height), l2depth); + lastLevel = MAX2(MAX2(l2width, l2height), l2depth); } + /* Save the level=0 dimensions */ + stObj->width0 = width; + stObj->height0 = height; + stObj->depth0 = depth; + fmt = st_mesa_format_to_pipe_format(stImage->base.TexFormat); - usage = default_usage(fmt); + bindings = default_bindings(st, fmt); stObj->pt = st_texture_create(st, gl_target_to_pipe(stObj->base.Target), @@ -320,7 +350,7 @@ guess_and_alloc_texture(struct st_context *st, width, height, depth, - usage); + bindings); DBG("%s - success\n", __FUNCTION__); } @@ -381,7 +411,8 @@ compress_with_blit(GLcontext * ctx, { const GLuint dstImageOffsets[1] = {0}; struct st_texture_image *stImage = st_texture_image(texImage); - struct pipe_context *pipe = ctx->st->pipe; + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; struct pipe_screen *screen = pipe->screen; gl_format mesa_format; struct pipe_resource templ; @@ -458,7 +489,7 @@ compress_with_blit(GLcontext * ctx, /* copy / compress image */ - util_blit_pixels_tex(ctx->st->blit, + util_blit_pixels_tex(st->blit, src_view, /* sampler view (src) */ 0, 0, /* src x0, y0 */ width, height, /* src x1, y1 */ @@ -493,7 +524,8 @@ st_TexImage(GLcontext * ctx, struct gl_texture_image *texImage, GLsizei imageSize, GLboolean compressed_src) { - struct pipe_screen *screen = ctx->st->pipe->screen; + struct st_context *st = st_context(ctx); + struct pipe_screen *screen = st->pipe->screen; struct st_texture_object *stObj = st_texture_object(texObj); struct st_texture_image *stImage = st_texture_image(texImage); GLint postConvWidth, postConvHeight; @@ -570,15 +602,13 @@ st_TexImage(GLcontext * ctx, * mipmap. If so, free the old mipmap. */ if (stObj->pt) { - if (stObj->teximage_realloc || - level > (GLint) stObj->pt->last_level || + if (level > (GLint) stObj->pt->last_level || !st_texture_match_image(stObj->pt, &stImage->base, stImage->face, stImage->level)) { DBG("release it\n"); pipe_resource_reference(&stObj->pt, NULL); assert(!stObj->pt); pipe_sampler_view_reference(&stObj->sampler_view, NULL); - stObj->teximage_realloc = FALSE; } } @@ -588,13 +618,13 @@ st_TexImage(GLcontext * ctx, } if (!stObj->pt) { - guess_and_alloc_texture(ctx->st, stObj, stImage); + guess_and_alloc_texture(st, stObj, stImage); if (!stObj->pt) { /* Probably out of memory. * Try flushing any pending rendering, then retry. */ - st_finish(ctx->st); - guess_and_alloc_texture(ctx->st, stObj, stImage); + st_finish(st); + guess_and_alloc_texture(st, stObj, stImage); if (!stObj->pt) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); return; @@ -659,7 +689,7 @@ st_TexImage(GLcontext * ctx, else transfer_usage = PIPE_TRANSFER_WRITE; - texImage->Data = st_texture_image_map(ctx->st, stImage, 0, + texImage->Data = st_texture_image_map(st, stImage, 0, transfer_usage, 0, 0, stImage->base.Width, stImage->base.Height); @@ -740,9 +770,9 @@ st_TexImage(GLcontext * ctx, if (stImage->pt && i + 1 < depth) { /* unmap this slice */ - st_texture_image_unmap(ctx->st, stImage); + st_texture_image_unmap(st, stImage); /* map next slice of 3D texture */ - texImage->Data = st_texture_image_map(ctx->st, stImage, i + 1, + texImage->Data = st_texture_image_map(st, stImage, i + 1, transfer_usage, 0, 0, stImage->base.Width, stImage->base.Height); @@ -755,7 +785,7 @@ done: _mesa_unmap_teximage_pbo(ctx, unpack); if (stImage->pt && texImage->Data) { - st_texture_image_unmap(ctx->st, stImage); + st_texture_image_unmap(st, stImage); texImage->Data = NULL; } } @@ -832,7 +862,8 @@ decompress_with_blit(GLcontext * ctx, GLenum target, GLint level, struct gl_texture_object *texObj, struct gl_texture_image *texImage) { - struct pipe_context *pipe = ctx->st->pipe; + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; struct pipe_screen *screen = pipe->screen; struct st_texture_image *stImage = st_texture_image(texImage); struct st_texture_object *stObj = st_texture_object(texObj); @@ -856,7 +887,7 @@ decompress_with_blit(GLcontext * ctx, GLenum target, GLint level, } /* blit/render/decompress */ - util_blit_pixels_tex(ctx->st->blit, + util_blit_pixels_tex(st->blit, src_view, /* pipe_resource (src) */ 0, 0, /* src x0, y0 */ width, height, /* src x1, y1 */ @@ -928,6 +959,7 @@ st_get_tex_image(GLcontext * ctx, GLenum target, GLint level, struct gl_texture_object *texObj, struct gl_texture_image *texImage, GLboolean compressed_dst) { + struct st_context *st = st_context(ctx); struct st_texture_image *stImage = st_texture_image(texImage); const GLuint dstImageStride = _mesa_image_image_stride(&ctx->Pack, texImage->Width, texImage->Height, @@ -954,14 +986,17 @@ st_get_tex_image(GLcontext * ctx, GLenum target, GLint level, */ unsigned face = _mesa_tex_target_to_face(target); - st_teximage_flush_before_map(ctx->st, stImage->pt, face, level, + st_teximage_flush_before_map(st, stImage->pt, face, level, PIPE_TRANSFER_READ); - texImage->Data = st_texture_image_map(ctx->st, stImage, 0, + texImage->Data = st_texture_image_map(st, stImage, 0, PIPE_TRANSFER_READ, 0, 0, stImage->base.Width, stImage->base.Height); - texImage->RowStride = stImage->transfer->stride / util_format_get_blocksize(stImage->pt->format); + /* compute stride in texels from stride in bytes */ + texImage->RowStride = stImage->transfer->stride + * util_format_get_blockwidth(stImage->pt->format) + / util_format_get_blocksize(stImage->pt->format); } else { /* Otherwise, the image should actually be stored in @@ -992,9 +1027,9 @@ st_get_tex_image(GLcontext * ctx, GLenum target, GLint level, if (stImage->pt && i + 1 < depth) { /* unmap this slice */ - st_texture_image_unmap(ctx->st, stImage); + st_texture_image_unmap(st, stImage); /* map next slice of 3D texture */ - texImage->Data = st_texture_image_map(ctx->st, stImage, i + 1, + texImage->Data = st_texture_image_map(st, stImage, i + 1, PIPE_TRANSFER_READ, 0, 0, stImage->base.Width, stImage->base.Height); @@ -1006,7 +1041,7 @@ st_get_tex_image(GLcontext * ctx, GLenum target, GLint level, /* Unmap */ if (stImage->pt) { - st_texture_image_unmap(ctx->st, stImage); + st_texture_image_unmap(st, stImage); texImage->Data = NULL; } } @@ -1044,7 +1079,8 @@ st_TexSubimage(GLcontext *ctx, GLint dims, GLenum target, GLint level, struct gl_texture_object *texObj, struct gl_texture_image *texImage) { - struct pipe_screen *screen = ctx->st->pipe->screen; + struct st_context *st = st_context(ctx); + struct pipe_screen *screen = st->pipe->screen; struct st_texture_image *stImage = st_texture_image(texImage); GLuint dstRowStride; const GLuint srcImageStride = @@ -1092,9 +1128,9 @@ st_TexSubimage(GLcontext *ctx, GLint dims, GLenum target, GLint level, else transfer_usage = PIPE_TRANSFER_WRITE; - st_teximage_flush_before_map(ctx->st, stImage->pt, face, level, + st_teximage_flush_before_map(st, stImage->pt, face, level, transfer_usage); - texImage->Data = st_texture_image_map(ctx->st, stImage, zoffset, + texImage->Data = st_texture_image_map(st, stImage, zoffset, transfer_usage, xoffset, yoffset, width, height); @@ -1122,9 +1158,9 @@ st_TexSubimage(GLcontext *ctx, GLint dims, GLenum target, GLint level, if (stImage->pt && i + 1 < depth) { /* unmap this slice */ - st_texture_image_unmap(ctx->st, stImage); + st_texture_image_unmap(st, stImage); /* map next slice of 3D texture */ - texImage->Data = st_texture_image_map(ctx->st, stImage, + texImage->Data = st_texture_image_map(st, stImage, zoffset + i + 1, transfer_usage, xoffset, yoffset, @@ -1137,7 +1173,7 @@ done: _mesa_unmap_teximage_pbo(ctx, packing); if (stImage->pt && texImage->Data) { - st_texture_image_unmap(ctx->st, stImage); + st_texture_image_unmap(st, stImage); texImage->Data = NULL; } } @@ -1208,6 +1244,7 @@ st_CompressedTexSubImage2D(GLcontext *ctx, GLenum target, GLint level, struct gl_texture_object *texObj, struct gl_texture_image *texImage) { + struct st_context *st = st_context(ctx); struct st_texture_image *stImage = st_texture_image(texImage); int srcBlockStride; int dstBlockStride; @@ -1218,9 +1255,9 @@ st_CompressedTexSubImage2D(GLcontext *ctx, GLenum target, GLint level, unsigned face = _mesa_tex_target_to_face(target); pformat = stImage->pt->format; - st_teximage_flush_before_map(ctx->st, stImage->pt, face, level, + st_teximage_flush_before_map(st, stImage->pt, face, level, PIPE_TRANSFER_WRITE); - texImage->Data = st_texture_image_map(ctx->st, stImage, 0, + texImage->Data = st_texture_image_map(st, stImage, 0, PIPE_TRANSFER_WRITE, xoffset, yoffset, width, height); @@ -1252,7 +1289,7 @@ st_CompressedTexSubImage2D(GLcontext *ctx, GLenum target, GLint level, } if (stImage->pt) { - st_texture_image_unmap(ctx->st, stImage); + st_texture_image_unmap(st, stImage); texImage->Data = NULL; } } @@ -1288,7 +1325,8 @@ fallback_copy_texsubimage(GLcontext *ctx, GLenum target, GLint level, GLint srcX, GLint srcY, GLsizei width, GLsizei height) { - struct pipe_context *pipe = ctx->st->pipe; + 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; @@ -1316,10 +1354,10 @@ fallback_copy_texsubimage(GLcontext *ctx, GLenum target, GLint level, else transfer_usage = PIPE_TRANSFER_WRITE; - st_teximage_flush_before_map(ctx->st, stImage->pt, 0, 0, + st_teximage_flush_before_map(st, stImage->pt, 0, 0, transfer_usage); - texDest = st_texture_image_map(ctx->st, stImage, 0, transfer_usage, + texDest = st_texture_image_map(st, stImage, 0, transfer_usage, destX, destY, width, height); if (baseFormat == GL_DEPTH_COMPONENT || @@ -1394,7 +1432,7 @@ fallback_copy_texsubimage(GLcontext *ctx, GLenum target, GLint level, free(tempSrc); } - st_texture_image_unmap(ctx->st, stImage); + st_texture_image_unmap(st, stImage); pipe->transfer_destroy(pipe, src_trans); } @@ -1490,7 +1528,8 @@ st_copy_texsubimage(GLcontext *ctx, const GLenum texBaseFormat = texImage->_BaseFormat; struct gl_framebuffer *fb = ctx->ReadBuffer; struct st_renderbuffer *strb; - struct pipe_context *pipe = ctx->st->pipe; + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; struct pipe_screen *screen = pipe->screen; enum pipe_format dest_format, src_format; GLboolean use_fallback = GL_TRUE; @@ -1500,11 +1539,11 @@ st_copy_texsubimage(GLcontext *ctx, 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); + st_flush(st, PIPE_FLUSH_RENDER_CACHE, NULL); /* make sure finalize_textures has been called? */ - if (0) st_validate_state(ctx->st); + if (0) st_validate_state(st); /* determine if copying depth or color data */ if (texBaseFormat == GL_DEPTH_COMPONENT || @@ -1621,7 +1660,7 @@ st_copy_texsubimage(GLcontext *ctx, srcY0 = srcY; srcY1 = srcY0 + height; } - util_blit_pixels_writemask(ctx->st->blit, + util_blit_pixels_writemask(st->blit, strb->surface, st_get_renderbuffer_sampler_view(strb, pipe), srcX, srcY0, @@ -1737,12 +1776,26 @@ st_CopyTexSubImage3D(GLcontext * ctx, GLenum target, GLint level, } +/** + * Copy image data from stImage into the texture object 'stObj' at level + * 'dstLevel'. + */ static void copy_image_data_to_texture(struct st_context *st, struct st_texture_object *stObj, GLuint dstLevel, struct st_texture_image *stImage) { + /* debug checks */ + { + const struct gl_texture_image *dstImage = + stObj->base.Image[stImage->face][stImage->level]; + assert(dstImage); + assert(dstImage->Width == stImage->base.Width); + assert(dstImage->Height == stImage->base.Height); + assert(dstImage->Depth == stImage->base.Depth); + } + if (stImage->pt) { /* Copy potentially with the blitter: */ @@ -1788,10 +1841,12 @@ st_finalize_texture(GLcontext *ctx, struct gl_texture_object *tObj, GLboolean *needFlush) { + struct st_context *st = st_context(ctx); struct st_texture_object *stObj = st_texture_object(tObj); const GLuint nr_faces = (stObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; - GLuint blockSize, face; + GLuint face; struct st_texture_image *firstImage; + enum pipe_format firstImageFormat; *needFlush = GL_FALSE; @@ -1806,10 +1861,11 @@ st_finalize_texture(GLcontext *ctx, stObj->base.MinFilter == GL_NEAREST) stObj->lastLevel = stObj->base.BaseLevel; else - stObj->lastLevel = stObj->base._MaxLevel - stObj->base.BaseLevel; + stObj->lastLevel = stObj->base._MaxLevel; } firstImage = st_texture_image(stObj->base.Image[0][stObj->base.BaseLevel]); + assert(firstImage); /* If both firstImage and stObj point to a texture which can contain * all active images, favour firstImage. Note that because of the @@ -1823,43 +1879,42 @@ st_finalize_texture(GLcontext *ctx, pipe_sampler_view_reference(&stObj->sampler_view, NULL); } - /* bytes per pixel block (blocks are usually 1x1) */ - blockSize = _mesa_get_format_bytes(firstImage->base.TexFormat); + /* Find gallium format for the Mesa texture */ + firstImageFormat = st_mesa_format_to_pipe_format(firstImage->base.TexFormat); /* If we already have a gallium texture, check that it matches the texture * object's format, target, size, num_levels, etc. */ if (stObj->pt) { - const enum pipe_format fmt = - st_mesa_format_to_pipe_format(firstImage->base.TexFormat); if (stObj->pt->target != gl_target_to_pipe(stObj->base.Target) || - stObj->pt->format != fmt || - stObj->pt->last_level < stObj->lastLevel || - stObj->pt->width0 != firstImage->base.Width2 || - stObj->pt->height0 != firstImage->base.Height2 || - stObj->pt->depth0 != firstImage->base.Depth2) + stObj->pt->format != firstImageFormat || + stObj->pt->last_level != stObj->lastLevel || + stObj->pt->width0 != stObj->width0 || + stObj->pt->height0 != stObj->height0 || + stObj->pt->depth0 != stObj->depth0) { + /* The gallium texture does not match the Mesa texture so delete the + * gallium texture now. We'll make a new one below. + */ pipe_resource_reference(&stObj->pt, NULL); pipe_sampler_view_reference(&stObj->sampler_view, NULL); - ctx->st->dirty.st |= ST_NEW_FRAMEBUFFER; + st->dirty.st |= ST_NEW_FRAMEBUFFER; } } /* May need to create a new gallium texture: */ if (!stObj->pt) { - const enum pipe_format fmt = - st_mesa_format_to_pipe_format(firstImage->base.TexFormat); - GLuint usage = default_usage(fmt); + GLuint bindings = default_bindings(st, firstImageFormat); - stObj->pt = st_texture_create(ctx->st, + stObj->pt = st_texture_create(st, gl_target_to_pipe(stObj->base.Target), - fmt, + firstImageFormat, stObj->lastLevel, - firstImage->base.Width2, - firstImage->base.Height2, - firstImage->base.Depth2, - usage); + stObj->width0, + stObj->height0, + stObj->depth0, + bindings); if (!stObj->pt) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); @@ -1873,12 +1928,12 @@ st_finalize_texture(GLcontext *ctx, GLuint level; for (level = 0; level <= stObj->lastLevel; level++) { struct st_texture_image *stImage = - st_texture_image(stObj->base.Image[face][stObj->base.BaseLevel + level]); + st_texture_image(stObj->base.Image[face][level]); /* Need to import images in main memory or held in other textures. */ if (stImage && stObj->pt != stImage->pt) { - copy_image_data_to_texture(ctx->st, stObj, level, stImage); + copy_image_data_to_texture(st, stObj, level, stImage); *needFlush = GL_TRUE; } } |