diff options
author | Nicolai Haehnle <nhaehnle@gmail.com> | 2008-08-19 22:02:41 +0200 |
---|---|---|
committer | Nicolai Haehnle <nhaehnle@gmail.com> | 2008-09-28 18:02:39 +0200 |
commit | 857362ef14fc4f175a9d425a74f9ca2b691971d6 (patch) | |
tree | e5c523f81461786db7ccce7711ae740b9f041d52 | |
parent | b3153fc6f7823b434ab82faec4e966c3311f8ce8 (diff) |
r300: Reasonably hacked up texture images
-rw-r--r-- | src/mesa/drivers/dri/r300/r300_context.h | 35 | ||||
-rw-r--r-- | src/mesa/drivers/dri/r300/r300_mipmap_tree.c | 224 | ||||
-rw-r--r-- | src/mesa/drivers/dri/r300/r300_mipmap_tree.h | 22 | ||||
-rw-r--r-- | src/mesa/drivers/dri/r300/r300_state.c | 4 | ||||
-rw-r--r-- | src/mesa/drivers/dri/r300/r300_tex.c | 498 | ||||
-rw-r--r-- | src/mesa/drivers/dri/r300/r300_tex.h | 5 | ||||
-rw-r--r-- | src/mesa/drivers/dri/r300/r300_texmem.c | 47 | ||||
-rw-r--r-- | src/mesa/drivers/dri/r300/r300_texstate.c | 382 | ||||
-rw-r--r-- | src/mesa/drivers/dri/r300/radeon_span.c | 10 |
9 files changed, 684 insertions, 543 deletions
diff --git a/src/mesa/drivers/dri/r300/r300_context.h b/src/mesa/drivers/dri/r300/r300_context.h index 047caaeb4d..59bfd9c595 100644 --- a/src/mesa/drivers/dri/r300/r300_context.h +++ b/src/mesa/drivers/dri/r300/r300_context.h @@ -144,16 +144,45 @@ struct r300_dma { GLuint nr_released_bufs; }; - /* Texture related */ - +/* Texture related */ typedef struct r300_tex_obj r300TexObj, *r300TexObjPtr; +typedef struct _r300_texture_image r300_texture_image; + + +struct _r300_texture_image { + struct gl_texture_image base; + + /** + * If mt != 0, the image is stored in hardware format in the + * given mipmap tree. In this case, base.Data may point into the + * mapping of the buffer object that contains the mipmap tree. + * + * If mt == 0, the image is stored in normal memory pointed to + * by base.Data. + */ + struct _r300_mipmap_tree *mt; + + int mtlevel; /** if mt != 0, this is the image's level in the mipmap tree */ + int mtface; /** if mt != 0, this is the image's face in the mipmap tree */ +}; + +static INLINE r300_texture_image *get_r300_texture_image(struct gl_texture_image *image) +{ + return (r300_texture_image*)image; +} + /* Texture object in locally shared texture space. */ struct r300_tex_obj { struct gl_texture_object base; struct _r300_mipmap_tree *mt; - GLuint dirty_images[6]; + + /** + * This is true if we've verified that the mipmap tree above is complete + * and so on. + */ + GLboolean validated; GLboolean image_override; /* Image overridden by GLX_EXT_tfp */ GLuint override_offset; diff --git a/src/mesa/drivers/dri/r300/r300_mipmap_tree.c b/src/mesa/drivers/dri/r300/r300_mipmap_tree.c index c3b918c4d9..c27e9b8aba 100644 --- a/src/mesa/drivers/dri/r300/r300_mipmap_tree.c +++ b/src/mesa/drivers/dri/r300/r300_mipmap_tree.c @@ -72,19 +72,28 @@ static void compute_tex_image_offset(r300_mipmap_tree *mt, /* Find image size in bytes */ if (mt->compressed) { + /* TODO: Is this correct? Need test cases for compressed textures! */ + GLuint align; + + if (mt->target == GL_TEXTURE_RECTANGLE_NV) + align = 64 / mt->bpp; + else + align = 32 / mt->bpp; + lvl->rowstride = (lvl->width + align - 1) & ~(align - 1); lvl->size = r300_compressed_texture_size(mt->r300->radeon.glCtx, lvl->width, lvl->height, lvl->depth, mt->compressed); } else if (mt->target == GL_TEXTURE_RECTANGLE_NV) { - lvl->size = ((lvl->width * mt->bpp + 63) & ~63) * lvl->height; + lvl->rowstride = (lvl->width * mt->bpp + 63) & ~63; + lvl->size = lvl->rowstride * lvl->height; } else if (mt->tilebits & R300_TXO_MICRO_TILE) { /* tile pattern is 16 bytes x2. mipmaps stay 32 byte aligned, * though the actual offset may be different (if texture is less than * 32 bytes width) to the untiled case */ - int w = (lvl->width * mt->bpp * 2 + 31) & ~31; - lvl->size = (w * ((lvl->height + 1) / 2)) * lvl->depth; + lvl->rowstride = (lvl->width * mt->bpp * 2 + 31) & ~31; + lvl->size = lvl->rowstride * ((lvl->height + 1) / 2) * lvl->depth; } else { - int w = (lvl->width * mt->bpp + 31) & ~31; - lvl->size = w * lvl->height * lvl->depth; + lvl->rowstride = (lvl->width * mt->bpp + 31) & ~31; + lvl->size = lvl->rowstride * lvl->height * lvl->depth; } assert(lvl->size > 0); @@ -115,9 +124,9 @@ static void calculate_miptree_layout(r300_mipmap_tree *mt) for(i = 0; i < numLevels; i++) { GLuint face; - mt->levels[i].width = minify(mt->width0, mt->firstLevel + i); - mt->levels[i].height = minify(mt->height0, mt->firstLevel + i); - mt->levels[i].depth = minify(mt->depth0, mt->firstLevel + i); + mt->levels[i].width = minify(mt->width0, i); + mt->levels[i].height = minify(mt->height0, i); + mt->levels[i].depth = minify(mt->depth0, i); for(face = 0; face < mt->faces; face++) compute_tex_image_offset(mt, face, i, &curOffset); @@ -139,6 +148,7 @@ r300_mipmap_tree* r300_miptree_create(r300ContextPtr rmesa, r300TexObj *t, r300_mipmap_tree *mt = CALLOC_STRUCT(_r300_mipmap_tree); mt->r300 = rmesa; + mt->refcount = 1; mt->t = t; mt->target = target; mt->faces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; @@ -158,91 +168,149 @@ r300_mipmap_tree* r300_miptree_create(r300ContextPtr rmesa, r300TexObj *t, return mt; } -/** - * Destroy the given mipmap tree. - */ -void r300_miptree_destroy(r300_mipmap_tree *mt) +void r300_miptree_reference(r300_mipmap_tree *mt) { - dri_bo_unreference(mt->bo); - free(mt); + mt->refcount++; + assert(mt->refcount > 0); } -/* - * XXX Move this into core Mesa? - */ -static void -_mesa_copy_rect(GLubyte * dst, - GLuint cpp, - GLuint dst_pitch, - GLuint dst_x, - GLuint dst_y, - GLuint width, - GLuint height, - const GLubyte * src, - GLuint src_pitch, GLuint src_x, GLuint src_y) +void r300_miptree_unreference(r300_mipmap_tree *mt) +{ + if (!mt) + return; + + assert(mt->refcount > 0); + mt->refcount--; + if (!mt->refcount) { + dri_bo_unreference(mt->bo); + free(mt); + } +} + + +static void calculate_first_last_level(struct gl_texture_object *tObj, + GLuint *pfirstLevel, GLuint *plastLevel) { - GLuint i; - - dst_pitch *= cpp; - src_pitch *= cpp; - dst += dst_x * cpp; - src += src_x * cpp; - dst += dst_y * dst_pitch; - src += src_y * dst_pitch; - width *= cpp; - - if (width == dst_pitch && width == src_pitch) - memcpy(dst, src, height * width); - else { - for (i = 0; i < height; i++) { - memcpy(dst, src, width); - dst += dst_pitch; - src += src_pitch; - } - } + const struct gl_texture_image * const baseImage = + tObj->Image[0][tObj->BaseLevel]; + + /* These must be signed values. MinLod and MaxLod can be negative numbers, + * and having firstLevel and lastLevel as signed prevents the need for + * extra sign checks. + */ + int firstLevel; + int lastLevel; + + /* Yes, this looks overly complicated, but it's all needed. + */ + switch (tObj->Target) { + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_3D: + case GL_TEXTURE_CUBE_MAP: + if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) { + /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL. + */ + firstLevel = lastLevel = tObj->BaseLevel; + } else { + firstLevel = tObj->BaseLevel + (GLint)(tObj->MinLod + 0.5); + firstLevel = MAX2(firstLevel, tObj->BaseLevel); + firstLevel = MIN2(firstLevel, tObj->BaseLevel + baseImage->MaxLog2); + lastLevel = tObj->BaseLevel + (GLint)(tObj->MaxLod + 0.5); + lastLevel = MAX2(lastLevel, tObj->BaseLevel); + lastLevel = MIN2(lastLevel, tObj->BaseLevel + baseImage->MaxLog2); + lastLevel = MIN2(lastLevel, tObj->MaxLevel); + lastLevel = MAX2(firstLevel, lastLevel); /* need at least one level */ + } + break; + case GL_TEXTURE_RECTANGLE_NV: + case GL_TEXTURE_4D_SGIS: + firstLevel = lastLevel = 0; + break; + default: + return; + } + + /* save these values */ + *pfirstLevel = firstLevel; + *plastLevel = lastLevel; } + /** - * Upload the given texture image to the given face/level of the mipmap tree. - * \param level of the texture, i.e. \c level==mt->firstLevel is the first hw level + * Checks whether the given miptree can hold the given texture image at the + * given face and level. */ -void r300_miptree_upload_image(r300_mipmap_tree *mt, GLuint face, GLuint level, - struct gl_texture_image *texImage) +GLboolean r300_miptree_matches_image(r300_mipmap_tree *mt, + struct gl_texture_image *texImage, GLuint face, GLuint level) { - GLuint hwlevel = level - mt->firstLevel; - r300_mipmap_level *lvl = &mt->levels[hwlevel]; - void *dest; + r300_mipmap_level *lvl; - assert(face < mt->faces); - assert(level >= mt->firstLevel && level <= mt->lastLevel); - assert(texImage && texImage->Data); - assert(texImage->Width == lvl->width); - assert(texImage->Height == lvl->height); - assert(texImage->Depth == lvl->depth); + if (face >= mt->faces || level < mt->firstLevel || level > mt->lastLevel) + return GL_FALSE; - dri_bo_map(mt->bo, GL_TRUE); + if (texImage->TexFormat->TexelBytes != mt->bpp) + return GL_FALSE; - dest = mt->bo->virtual + lvl->faces[face].offset; + lvl = &mt->levels[level - mt->firstLevel]; + if (lvl->width != texImage->Width || + lvl->height != texImage->Height || + lvl->depth != texImage->Depth) + return GL_FALSE; - if (mt->tilebits) - WARN_ONCE("%s: tiling not supported yet", __FUNCTION__); + return GL_TRUE; +} - if (!mt->compressed) { - GLuint dst_align; - GLuint dst_pitch = lvl->width; - GLuint src_pitch = lvl->width; - if (mt->target == GL_TEXTURE_RECTANGLE_NV) - dst_align = 64 / mt->bpp; - else - dst_align = 32 / mt->bpp; - dst_pitch = (dst_pitch + dst_align - 1) & ~(dst_align - 1); +/** + * Checks whether the given miptree has the right format to store the given texture object. + */ +GLboolean r300_miptree_matches_texture(r300_mipmap_tree *mt, struct gl_texture_object *texObj) +{ + struct gl_texture_image *firstImage; + GLuint compressed; + GLuint numfaces = 1; + GLuint firstLevel, lastLevel; + + calculate_first_last_level(texObj, &firstLevel, &lastLevel); + if (texObj->Target == GL_TEXTURE_CUBE_MAP) + numfaces = 6; + + firstImage = texObj->Image[0][firstLevel]; + compressed = firstImage->IsCompressed ? firstImage->TexFormat->MesaFormat : 0; + + return (mt->firstLevel == firstLevel && + mt->lastLevel == lastLevel && + mt->width0 == firstImage->Width && + mt->height0 == firstImage->Height && + mt->depth0 == firstImage->Depth && + mt->bpp == firstImage->TexFormat->TexelBytes && + mt->compressed == compressed); +} - _mesa_copy_rect(dest, mt->bpp, dst_pitch, 0, 0, lvl->width, lvl->height, - texImage->Data, src_pitch, 0, 0); - } else { - memcpy(dest, texImage->Data, lvl->size); - } - dri_bo_unmap(mt->bo); +/** + * Try to allocate a mipmap tree for the given texture that will fit the + * given image in the given position. + */ +void r300_try_alloc_miptree(r300ContextPtr rmesa, r300TexObj *t, + struct gl_texture_image *texImage, GLuint face, GLuint level) +{ + GLuint compressed = texImage->IsCompressed ? texImage->TexFormat->MesaFormat : 0; + GLuint numfaces = 1; + GLuint firstLevel, lastLevel; + + assert(!t->mt); + + calculate_first_last_level(&t->base, &firstLevel, &lastLevel); + if (t->base.Target == GL_TEXTURE_CUBE_MAP) + numfaces = 6; + + if (level != firstLevel || face >= numfaces) + return; + + t->mt = r300_miptree_create(rmesa, t, t->base.Target, + firstLevel, lastLevel, + texImage->Width, texImage->Height, texImage->Depth, + texImage->TexFormat->TexelBytes, t->tile_bits, compressed); } diff --git a/src/mesa/drivers/dri/r300/r300_mipmap_tree.h b/src/mesa/drivers/dri/r300/r300_mipmap_tree.h index a888ecfff1..7705a4d8c9 100644 --- a/src/mesa/drivers/dri/r300/r300_mipmap_tree.h +++ b/src/mesa/drivers/dri/r300/r300_mipmap_tree.h @@ -35,7 +35,7 @@ typedef struct _r300_mipmap_level r300_mipmap_level; typedef struct _r300_mipmap_image r300_mipmap_image; struct _r300_mipmap_image { - GLuint offset; /** Offset of this image from the start of mipmap tree, in bytes */ + GLuint offset; /** Offset of this image from the start of mipmap tree buffer, in bytes */ }; struct _r300_mipmap_level { @@ -43,6 +43,7 @@ struct _r300_mipmap_level { GLuint height; GLuint depth; GLuint size; /** Size of each image, in bytes */ + GLuint rowstride; /** in bytes */ r300_mipmap_image faces[6]; }; @@ -59,6 +60,7 @@ struct _r300_mipmap_tree { r300ContextPtr r300; r300TexObj *t; dri_bo *bo; + GLuint refcount; GLuint totalsize; /** total size of the miptree, in bytes */ @@ -67,9 +69,9 @@ struct _r300_mipmap_tree { GLuint firstLevel; /** First mip level stored in this mipmap tree */ GLuint lastLevel; /** Last mip level stored in this mipmap tree */ - GLuint width0; /** Width of level 0 image */ - GLuint height0; /** Height of level 0 image */ - GLuint depth0; /** Depth of level 0 image */ + GLuint width0; /** Width of firstLevel image */ + GLuint height0; /** Height of firstLevel image */ + GLuint depth0; /** Depth of firstLevel image */ GLuint bpp; /** Bytes per texel */ GLuint tilebits; /** R300_TXO_xxx_TILE */ @@ -82,10 +84,14 @@ r300_mipmap_tree* r300_miptree_create(r300ContextPtr rmesa, r300TexObj *t, GLenum target, GLuint firstLevel, GLuint lastLevel, GLuint width0, GLuint height0, GLuint depth0, GLuint bpp, GLuint tilebits, GLuint compressed); -void r300_miptree_destroy(r300_mipmap_tree *mt); - -void r300_miptree_upload_image(r300_mipmap_tree *mt, GLuint face, GLuint level, - struct gl_texture_image *texImage); +void r300_miptree_reference(r300_mipmap_tree *mt); +void r300_miptree_unreference(r300_mipmap_tree *mt); + +GLboolean r300_miptree_matches_image(r300_mipmap_tree *mt, + struct gl_texture_image *texImage, GLuint face, GLuint level); +GLboolean r300_miptree_matches_texture(r300_mipmap_tree *mt, struct gl_texture_object *texObj); +void r300_try_alloc_miptree(r300ContextPtr rmesa, r300TexObj *t, + struct gl_texture_image *texImage, GLuint face, GLuint level); #endif /* __R300_MIPMAP_TREE_H_ */ diff --git a/src/mesa/drivers/dri/r300/r300_state.c b/src/mesa/drivers/dri/r300/r300_state.c index b31476449f..93f7568c82 100644 --- a/src/mesa/drivers/dri/r300/r300_state.c +++ b/src/mesa/drivers/dri/r300/r300_state.c @@ -2206,8 +2206,6 @@ static void r300ResetHwState(r300ContextPtr r300) r300UpdateCulling(ctx); - r300UpdateTextureState(ctx); - r300SetBlendState(ctx); r300SetLogicOpState(ctx); @@ -2630,7 +2628,7 @@ void r300UpdateShaderStates(r300ContextPtr rmesa) GLcontext *ctx; ctx = rmesa->radeon.glCtx; - r300UpdateTextureState(ctx); + r300ValidateTextures(ctx); r300SetEarlyZState(ctx); GLuint fgdepthsrc = R300_FG_DEPTH_SRC_SCAN; diff --git a/src/mesa/drivers/dri/r300/r300_tex.c b/src/mesa/drivers/dri/r300/r300_tex.c index c6ee1b5e02..3c10acc420 100644 --- a/src/mesa/drivers/dri/r300/r300_tex.c +++ b/src/mesa/drivers/dri/r300/r300_tex.c @@ -38,6 +38,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "context.h" #include "enums.h" #include "image.h" +#include "mipmap.h" #include "simple_list.h" #include "texformat.h" #include "texstore.h" @@ -119,6 +120,9 @@ static GLuint aniso_filter(GLfloat anisotropy) */ static void r300SetTexFilter(r300TexObjPtr t, GLenum minf, GLenum magf, GLfloat anisotropy) { + /* Force revalidation to account for switches from/to mipmapping. */ + t->validated = GL_FALSE; + t->filter &= ~(R300_TX_MIN_FILTER_MASK | R300_TX_MIN_FILTER_MIP_MASK | R300_TX_MAG_FILTER_MASK | R300_TX_MAX_ANISO_MASK); t->filter_1 &= ~R300_EDGE_ANISO_EDGE_ONLY; @@ -401,190 +405,204 @@ static const struct gl_texture_format *r300ChooseTextureFormat(GLcontext * ctx, return NULL; /* never get here */ } + /** - * Marks the given face/level pair as dirty. - * This will cause an appropriate texture reupload the next time this - * texture is validated. + * Allocate an empty texture image object. */ -static void mark_texture_image_dirty(r300TexObj *t, int face, int level) +static struct gl_texture_image *r300NewTextureImage(GLcontext *ctx) { - t->dirty_images[face] |= 1 << level; + return CALLOC(sizeof(r300_texture_image)); } -static void r300TexImage1D(GLcontext * ctx, GLenum target, GLint level, - GLint internalFormat, - GLint width, GLint border, - GLenum format, GLenum type, const GLvoid * pixels, - const struct gl_pixelstore_attrib *packing, - struct gl_texture_object *texObj, - struct gl_texture_image *texImage) +/** + * Free memory associated with this texture image. + */ +static void r300FreeTexImageData(GLcontext *ctx, struct gl_texture_image *timage) { - r300TexObj* t = r300_tex_obj(texObj); - - _mesa_store_teximage1d(ctx, target, level, internalFormat, - width, border, format, type, pixels, - &ctx->Unpack, texObj, texImage); + r300_texture_image* image = get_r300_texture_image(timage); - mark_texture_image_dirty(t, 0, level); + if (image->mt) { + r300_miptree_unreference(image->mt); + image->mt = 0; + assert(!image->base.Data); + } else { + _mesa_free_texture_image_data(ctx, timage); + } } -static void r300TexSubImage1D(GLcontext * ctx, GLenum target, GLint level, - GLint xoffset, - GLsizei width, - GLenum format, GLenum type, - const GLvoid * pixels, - const struct gl_pixelstore_attrib *packing, - struct gl_texture_object *texObj, - struct gl_texture_image *texImage) -{ - r300TexObj* t = r300_tex_obj(texObj); - - _mesa_store_texsubimage1d(ctx, target, level, xoffset, width, - format, type, pixels, packing, texObj, - texImage); - mark_texture_image_dirty(t, 0, level); +/* Set Data pointer and additional data for mapped texture image */ +static void teximage_set_map_data(r300_texture_image *image) +{ + r300_mipmap_level *lvl = &image->mt->levels[image->mtlevel]; + image->base.Data = image->mt->bo->virtual + lvl->faces[image->mtface].offset; + image->base.RowStride = lvl->rowstride / image->mt->bpp; } -static void r300TexImage2D(GLcontext * ctx, GLenum target, GLint level, - GLint internalFormat, - GLint width, GLint height, GLint border, - GLenum format, GLenum type, const GLvoid * pixels, - const struct gl_pixelstore_attrib *packing, - struct gl_texture_object *texObj, - struct gl_texture_image *texImage) + +/** + * Map a single texture image for glTexImage and friends. + */ +static void r300_teximage_map(r300_texture_image *image, GLboolean write_enable) { - r300TexObj* t = r300_tex_obj(texObj); - GLuint face; + if (image->mt) { + assert(!image->base.Data); - /* which cube face or ordinary 2D image */ - switch (target) { - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - face = - (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; - ASSERT(face < 6); - break; - default: - face = 0; + dri_bo_map(image->mt->bo, write_enable); + teximage_set_map_data(image); } +} - texImage->IsClientData = GL_FALSE; - - if (RADEON_DEBUG & DEBUG_TEXTURE) - fprintf(stderr, "%s: Using normal storage\n", - __FUNCTION__); - /* Normal path: copy (to cached memory) and eventually upload - * via another copy to GART memory and then a blit... Could - * eliminate one copy by going straight to (permanent) GART. - * - * Note, this will call r300ChooseTextureFormat. - */ - _mesa_store_teximage2d(ctx, target, level, internalFormat, - width, height, border, format, type, - pixels, &ctx->Unpack, texObj, texImage); +static void r300_teximage_unmap(r300_texture_image *image) +{ + if (image->mt) { + assert(image->base.Data); - mark_texture_image_dirty(t, face, level); + image->base.Data = 0; + dri_bo_unmap(image->mt->bo); + } } -static void r300TexSubImage2D(GLcontext * ctx, GLenum target, GLint level, - GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - const GLvoid * pixels, - const struct gl_pixelstore_attrib *packing, - struct gl_texture_object *texObj, - struct gl_texture_image *texImage) +/** + * Map a validated texture for reading during software rendering. + */ +static void r300MapTexture(GLcontext *ctx, struct gl_texture_object *texObj) { r300TexObj* t = r300_tex_obj(texObj); - GLuint face; + int face, level; - /* which cube face or ordinary 2D image */ - switch (target) { - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - face = - (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; - ASSERT(face < 6); - break; - default: - face = 0; + assert(texObj->_Complete); + assert(t->mt); + + dri_bo_map(t->mt->bo, GL_FALSE); + for(face = 0; face < t->mt->faces; ++face) { + for(level = t->mt->firstLevel; level <= t->mt->lastLevel; ++level) + teximage_set_map_data(get_r300_texture_image(texObj->Image[face][level])); } +} - _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width, - height, format, type, pixels, packing, texObj, - texImage); +static void r300UnmapTexture(GLcontext *ctx, struct gl_texture_object *texObj) +{ + r300TexObj* t = r300_tex_obj(texObj); + int face, level; - mark_texture_image_dirty(t, face, level); + assert(texObj->_Complete); + assert(t->mt); + + for(face = 0; face < t->mt->faces; ++face) { + for(level = t->mt->firstLevel; level <= t->mt->lastLevel; ++level) + texObj->Image[face][level]->Data = 0; + } + dri_bo_unmap(t->mt->bo); } -static void r300CompressedTexImage2D(GLcontext * ctx, GLenum target, - GLint level, GLint internalFormat, - GLint width, GLint height, GLint border, - GLsizei imageSize, const GLvoid * data, - struct gl_texture_object *texObj, - struct gl_texture_image *texImage) +/** + * All glTexImage calls go through this function. + */ +static void r300_teximage( + GLcontext *ctx, int dims, + GLint face, GLint level, + GLint internalFormat, + GLint width, GLint height, GLint 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) { + r300ContextPtr rmesa = R300_CONTEXT(ctx); r300TexObj* t = r300_tex_obj(texObj); - GLuint face; + r300_texture_image* image = get_r300_texture_image(texImage); - /* which cube face or ordinary 2D image */ - switch (target) { - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - face = - (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; - ASSERT(face < 6); - break; - default: - face = 0; + R300_FIREVERTICES(rmesa); + + t->validated = GL_FALSE; + + /* Choose and fill in the texture format for this image */ + texImage->TexFormat = r300ChooseTextureFormat(ctx, internalFormat, format, type); + _mesa_set_fetch_functions(texImage, dims); + + if (texImage->TexFormat->TexelBytes == 0) { + texImage->IsCompressed = GL_TRUE; + texImage->CompressedSize = + ctx->Driver.CompressedTextureSize(ctx, texImage->Width, + texImage->Height, texImage->Depth, + texImage->TexFormat->MesaFormat); + } else { + texImage->IsCompressed = GL_FALSE; + texImage->CompressedSize = 0; } - texImage->IsClientData = GL_FALSE; + /* Allocate memory for image */ + r300FreeTexImageData(ctx, texImage); /* Mesa core only clears texImage->Data but not image->mt */ - if (RADEON_DEBUG & DEBUG_TEXTURE) - fprintf(stderr, "%s: Using normal storage\n", - __FUNCTION__); + if (!t->mt) + r300_try_alloc_miptree(rmesa, t, texImage, face, level); + if (t->mt && r300_miptree_matches_image(t->mt, texImage, face, level)) { + image->mt = t->mt; + image->mtlevel = level - t->mt->firstLevel; + image->mtface = face; + r300_miptree_reference(t->mt); + } else { + int size; + if (texImage->IsCompressed) { + size = texImage->CompressedSize; + } else { + size = texImage->Width * texImage->Height * texImage->Depth * texImage->TexFormat->TexelBytes; + } + texImage->Data = _mesa_alloc_texmemory(size); + } - /* Normal path: copy (to cached memory) and eventually upload - * via another copy to GART memory and then a blit... Could - * eliminate one copy by going straight to (permanent) GART. - * - * Note, this will call r300ChooseTextureFormat. - */ - _mesa_store_compressed_teximage2d(ctx, target, level, - internalFormat, width, height, - border, imageSize, data, - texObj, texImage); + /* Upload texture image; note that the spec allows pixels to be NULL */ + if (compressed) { + pixels = _mesa_validate_pbo_compressed_teximage( + ctx, imageSize, pixels, packing, "glCompressedTexImage"); + } else { + pixels = _mesa_validate_pbo_teximage( + ctx, dims, width, height, depth, + format, type, pixels, packing, "glTexImage"); + } + + if (pixels) { + r300_teximage_map(image, GL_TRUE); - mark_texture_image_dirty(t, face, level); + if (compressed) { + memcpy(texImage->Data, pixels, imageSize); + } else { + GLuint dstRowStride; + if (image->mt) { + r300_mipmap_level *lvl = &image->mt->levels[image->mtlevel]; + dstRowStride = lvl->rowstride; + } else { + dstRowStride = texImage->Width * texImage->TexFormat->TexelBytes; + } + if (!texImage->TexFormat->StoreImage(ctx, dims, + texImage->_BaseFormat, + texImage->TexFormat, + texImage->Data, 0, 0, 0, /* dstX/Y/Zoffset */ + dstRowStride, + texImage->ImageOffsets, + width, height, depth, + format, type, pixels, packing)) + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); + } + + r300_teximage_unmap(image); + } + + _mesa_unmap_teximage_pbo(ctx, packing); + + /* SGIS_generate_mipmap */ + if (level == texObj->BaseLevel && texObj->GenerateMipmap) { + ctx->Driver.GenerateMipmap(ctx, texObj->Target, texObj); + } } -static void r300CompressedTexSubImage2D(GLcontext * ctx, GLenum target, - GLint level, GLint xoffset, - GLint yoffset, GLsizei width, - GLsizei height, GLenum format, - GLsizei imageSize, const GLvoid * data, - struct gl_texture_object *texObj, - struct gl_texture_image *texImage) -{ - r300TexObj* t = r300_tex_obj(texObj); - GLuint face; - /* which cube face or ordinary 2D image */ +static GLuint face_for_target(GLenum target) +{ switch (target) { case GL_TEXTURE_CUBE_MAP_POSITIVE_X: case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: @@ -592,19 +610,50 @@ static void r300CompressedTexSubImage2D(GLcontext * ctx, GLenum target, case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - face = - (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; - ASSERT(face < 6); - break; + return (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; default: - face = 0; + return 0; } +} + + +static void r300TexImage1D(GLcontext * ctx, GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint border, + GLenum format, GLenum type, const GLvoid * pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + r300_teximage(ctx, 1, 0, level, internalFormat, width, 1, 1, + 0, format, type, pixels, packing, texObj, texImage, 0); +} - _mesa_store_compressed_texsubimage2d(ctx, target, level, xoffset, - yoffset, width, height, format, - imageSize, data, texObj, texImage); +static void r300TexImage2D(GLcontext * ctx, GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint height, GLint border, + GLenum format, GLenum type, const GLvoid * pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + GLuint face = face_for_target(target); - mark_texture_image_dirty(t, face, level); + r300_teximage(ctx, 2, face, level, internalFormat, width, height, 1, + 0, format, type, pixels, packing, texObj, texImage, 0); +} + +static void r300CompressedTexImage2D(GLcontext * ctx, GLenum target, + GLint level, GLint internalFormat, + GLint width, GLint height, GLint border, + GLsizei imageSize, const GLvoid * data, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + GLuint face = face_for_target(target); + + r300_teximage(ctx, 2, face, level, internalFormat, width, height, 1, + imageSize, 0, 0, data, 0, texObj, texImage, 1); } static void r300TexImage3D(GLcontext * ctx, GLenum target, GLint level, @@ -616,26 +665,98 @@ static void r300TexImage3D(GLcontext * ctx, GLenum target, GLint level, struct gl_texture_object *texObj, struct gl_texture_image *texImage) { - r300TexObj* t = r300_tex_obj(texObj); + r300_teximage(ctx, 3, 0, level, internalFormat, width, height, depth, + 0, format, type, pixels, packing, texObj, texImage, 0); +} - texImage->IsClientData = GL_FALSE; +/** + * Update a subregion of the given texture image. + */ +static void r300_texsubimage(GLcontext* ctx, int dims, int level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + 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) +{ + r300ContextPtr rmesa = R300_CONTEXT(ctx); + r300_texture_image* image = get_r300_texture_image(texImage); - if (RADEON_DEBUG & DEBUG_TEXTURE) - fprintf(stderr, "%s: Using normal storage\n", - __FUNCTION__); + R300_FIREVERTICES(rmesa); - /* Normal path: copy (to cached memory) and eventually upload - * via another copy to GART memory and then a blit... Could - * eliminate one copy by going straight to (permanent) GART. - * - * Note, this will call r300ChooseTextureFormat. - */ - _mesa_store_teximage3d(ctx, target, level, internalFormat, - width, height, depth, border, - format, type, pixels, - &ctx->Unpack, texObj, texImage); + pixels = _mesa_validate_pbo_teximage(ctx, dims, + width, height, depth, format, type, pixels, packing, "glTexSubImage1D"); + + if (pixels) { + GLint dstRowStride; + r300_teximage_map(image, GL_TRUE); + + if (image->mt) { + r300_mipmap_level *lvl = &image->mt->levels[image->mtlevel]; + dstRowStride = lvl->rowstride; + } else { + dstRowStride = texImage->Width * texImage->TexFormat->TexelBytes; + } + + if (!texImage->TexFormat->StoreImage(ctx, dims, texImage->_BaseFormat, + texImage->TexFormat, texImage->Data, + xoffset, yoffset, zoffset, + dstRowStride, + texImage->ImageOffsets, + width, height, depth, + format, type, pixels, packing)) + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage"); + + r300_teximage_unmap(image); + } + + _mesa_unmap_teximage_pbo(ctx, packing); - mark_texture_image_dirty(t, 0, level); + /* GL_SGIS_generate_mipmap */ + if (level == texObj->BaseLevel && texObj->GenerateMipmap) { + ctx->Driver.GenerateMipmap(ctx, texObj->Target, texObj); + } +} + +static void r300TexSubImage1D(GLcontext * ctx, GLenum target, GLint level, + GLint xoffset, + GLsizei width, + GLenum format, GLenum type, + const GLvoid * pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + r300_texsubimage(ctx, 1, level, xoffset, 0, 0, width, 1, 1, + format, type, pixels, packing, texObj, texImage, 0); +} + +static void r300TexSubImage2D(GLcontext * ctx, GLenum target, GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const GLvoid * pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + r300_texsubimage(ctx, 2, level, xoffset, yoffset, 0, width, height, 1, + format, type, pixels, packing, texObj, texImage, 0); +} + +static void r300CompressedTexSubImage2D(GLcontext * ctx, GLenum target, + GLint level, GLint xoffset, + GLint yoffset, GLsizei width, + GLsizei height, GLenum format, + GLsizei imageSize, const GLvoid * data, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + r300_texsubimage(ctx, 2, level, xoffset, yoffset, 0, width, height, 1, + format, 0, data, 0, texObj, texImage, 1); } static void @@ -648,16 +769,29 @@ r300TexSubImage3D(GLcontext * ctx, GLenum target, GLint level, struct gl_texture_object *texObj, struct gl_texture_image *texImage) { - r300TexObj* t = r300_tex_obj(texObj); + r300_texsubimage(ctx, 3, level, xoffset, yoffset, zoffset, width, height, depth, + format, type, pixels, packing, texObj, texImage, 0); +} - _mesa_store_texsubimage3d(ctx, target, level, xoffset, yoffset, zoffset, - width, height, depth, - format, type, pixels, packing, texObj, - texImage); - mark_texture_image_dirty(t, 0, level); +/** + * Wraps Mesa's implementation to ensure that the base level image is mapped. + * + * This relies on internal details of _mesa_generate_mipmap, in particular + * the fact that the memory for recreated texture images is always freed. + */ +static void r300_generate_mipmap(GLcontext* ctx, GLenum target, struct gl_texture_object *texObj) +{ + GLuint face = face_for_target(target); + r300_texture_image *baseimage = get_r300_texture_image(texObj->Image[face][texObj->BaseLevel]); + + r300_teximage_map(baseimage, GL_FALSE); + _mesa_generate_mipmap(ctx, target, texObj); + r300_teximage_unmap(baseimage); } + + /** * Changes variables and flags for a state update, which will happen at the * next UpdateTextureState @@ -701,8 +835,9 @@ static void r300TexParameter(GLcontext * ctx, GLenum target, * to simulate a clamped LOD. */ if (t->mt) { - r300_miptree_destroy(t->mt); + r300_miptree_unreference(t->mt); t->mt = 0; + t->validated = GL_FALSE; } break; @@ -747,7 +882,7 @@ static void r300DeleteTexture(GLcontext * ctx, struct gl_texture_object *texObj) } if (t->mt) { - r300_miptree_destroy(t->mt); + r300_miptree_unreference(t->mt); t->mt = 0; } _mesa_delete_texture_object(ctx, texObj); @@ -789,6 +924,11 @@ void r300InitTextureFuncs(struct dd_function_table *functions) /* Note: we only plug in the functions we implement in the driver * since _mesa_init_driver_functions() was already called. */ + functions->NewTextureImage = r300NewTextureImage; + functions->FreeTexImageData = r300FreeTexImageData; + functions->MapTexture = r300MapTexture; + functions->UnmapTexture = r300UnmapTexture; + functions->ChooseTextureFormat = r300ChooseTextureFormat; functions->TexImage1D = r300TexImage1D; functions->TexImage2D = r300TexImage2D; @@ -805,5 +945,7 @@ void r300InitTextureFuncs(struct dd_function_table *functions) functions->CompressedTexImage2D = r300CompressedTexImage2D; functions->CompressedTexSubImage2D = r300CompressedTexSubImage2D; + functions->GenerateMipmap = r300_generate_mipmap; + driInitTextureFormats(); } diff --git a/src/mesa/drivers/dri/r300/r300_tex.h b/src/mesa/drivers/dri/r300/r300_tex.h index 5d7f21e88d..358b927828 100644 --- a/src/mesa/drivers/dri/r300/r300_tex.h +++ b/src/mesa/drivers/dri/r300/r300_tex.h @@ -41,10 +41,7 @@ extern void r300SetTexOffset(__DRIcontext *pDRICtx, GLint texname, unsigned long long offset, GLint depth, GLuint pitch); -extern void r300UpdateTextureState(GLcontext * ctx); - -extern int r300UploadTexImages(r300ContextPtr rmesa, r300TexObjPtr t, - GLuint face); +extern void r300ValidateTextures(GLcontext * ctx); extern void r300InitTextureFuncs(struct dd_function_table *functions); diff --git a/src/mesa/drivers/dri/r300/r300_texmem.c b/src/mesa/drivers/dri/r300/r300_texmem.c index b3b501babb..a45f2d4409 100644 --- a/src/mesa/drivers/dri/r300/r300_texmem.c +++ b/src/mesa/drivers/dri/r300/r300_texmem.c @@ -57,50 +57,3 @@ SOFTWARE. #include "r300_mem.h" - -/** - * Upload the texture images associated with texture \a t. This might - * require the allocation of texture memory. - * - * \param rmesa Context pointer - * \param t Texture to be uploaded - * \param face Cube map face to be uploaded. Zero for non-cube maps. - */ - -int r300UploadTexImages(r300ContextPtr rmesa, r300TexObjPtr t, GLuint face) -{ - if (t->image_override) - return 0; - if (!t->mt) - return 0; - - if (RADEON_DEBUG & (DEBUG_TEXTURE | DEBUG_IOCTL)) { - fprintf(stderr, "%s( %p, %p ) lvls=%d-%d\n", __FUNCTION__, - (void *)rmesa->radeon.glCtx, t, - t->mt->firstLevel, t->mt->lastLevel); - } - - if (RADEON_DEBUG & DEBUG_SYNC) { - fprintf(stderr, "%s: Syncing\n", __FUNCTION__); - radeonFinish(rmesa->radeon.glCtx); - } - - /* Upload any images that are new */ - if (t->dirty_images[face]) { - int i, numLevels = t->mt->lastLevel - t->mt->firstLevel + 1; - for (i = 0; i < numLevels; i++) { - if (t->dirty_images[face] & (1 << (i + t->mt->firstLevel))) { - r300_miptree_upload_image(t->mt, face, t->mt->firstLevel + i, - t->base.Image[face][t->mt->firstLevel + i]); - } - } - t->dirty_images[face] = 0; - } - - if (RADEON_DEBUG & DEBUG_SYNC) { - fprintf(stderr, "%s: Syncing\n", __FUNCTION__); - radeonFinish(rmesa->radeon.glCtx); - } - - return 0; -} diff --git a/src/mesa/drivers/dri/r300/r300_texstate.c b/src/mesa/drivers/dri/r300/r300_texstate.c index ae2c1fe8fe..f81f5b30fa 100644 --- a/src/mesa/drivers/dri/r300/r300_texstate.c +++ b/src/mesa/drivers/dri/r300/r300_texstate.c @@ -189,253 +189,227 @@ void r300SetDepthTexMode(struct gl_texture_object *tObj) } -static void calculate_first_last_level(struct gl_texture_object *tObj, - GLuint *pfirstLevel, GLuint *plastLevel) -{ - const struct gl_texture_image * const baseImage = - tObj->Image[0][tObj->BaseLevel]; - - /* These must be signed values. MinLod and MaxLod can be negative numbers, - * and having firstLevel and lastLevel as signed prevents the need for - * extra sign checks. - */ - int firstLevel; - int lastLevel; - - /* Yes, this looks overly complicated, but it's all needed. - */ - switch (tObj->Target) { - case GL_TEXTURE_1D: - case GL_TEXTURE_2D: - case GL_TEXTURE_3D: - case GL_TEXTURE_CUBE_MAP: - if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) { - /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL. - */ - firstLevel = lastLevel = tObj->BaseLevel; - } else { - firstLevel = tObj->BaseLevel + (GLint)(tObj->MinLod + 0.5); - firstLevel = MAX2(firstLevel, tObj->BaseLevel); - firstLevel = MIN2(firstLevel, tObj->BaseLevel + baseImage->MaxLog2); - lastLevel = tObj->BaseLevel + (GLint)(tObj->MaxLod + 0.5); - lastLevel = MAX2(lastLevel, tObj->BaseLevel); - lastLevel = MIN2(lastLevel, tObj->BaseLevel + baseImage->MaxLog2); - lastLevel = MIN2(lastLevel, tObj->MaxLevel); - lastLevel = MAX2(firstLevel, lastLevel); /* need at least one level */ - } - break; - case GL_TEXTURE_RECTANGLE_NV: - case GL_TEXTURE_4D_SGIS: - firstLevel = lastLevel = 0; - break; - default: - return; - } - - /* save these values */ - *pfirstLevel = firstLevel; - *plastLevel = lastLevel; -} - - /** - * This function ensures a validated miptree is available. - * - * Additionally, some texture format bits are configured here. + * Compute the cached hardware register values for the given texture object. * * \param rmesa Context pointer - * \param tObj GL texture object whose images are to be posted to - * hardware state. + * \param t the r300 texture object */ -static void r300SetTexImages(r300ContextPtr rmesa, - struct gl_texture_object *tObj) +static void setup_hardware_state(r300ContextPtr rmesa, r300TexObj *t) { - r300TexObjPtr t = r300_tex_obj(tObj); - const struct gl_texture_image *baseImage = - tObj->Image[0][tObj->BaseLevel]; - GLint texelBytes; - GLuint firstLevel = 0, lastLevel = 0; - - calculate_first_last_level(tObj, &firstLevel, &lastLevel); + const struct gl_texture_image *firstImage = + t->base.Image[0][t->mt->firstLevel]; - /* Set the hardware texture format - */ if (!t->image_override - && VALID_FORMAT(baseImage->TexFormat->MesaFormat)) { - if (baseImage->TexFormat->BaseFormat == GL_DEPTH_COMPONENT) { - r300SetDepthTexMode(tObj); + && VALID_FORMAT(firstImage->TexFormat->MesaFormat)) { + if (firstImage->TexFormat->BaseFormat == GL_DEPTH_COMPONENT) { + r300SetDepthTexMode(&t->base); } else { - t->format = tx_table[baseImage->TexFormat->MesaFormat].format; + t->format = tx_table[firstImage->TexFormat->MesaFormat].format; } - t->filter |= tx_table[baseImage->TexFormat->MesaFormat].filter; + t->filter |= tx_table[firstImage->TexFormat->MesaFormat].filter; } else if (!t->image_override) { _mesa_problem(NULL, "unexpected texture format in %s", __FUNCTION__); return; } - texelBytes = baseImage->TexFormat->TexelBytes; t->tile_bits = 0; - if (tObj->Target == GL_TEXTURE_CUBE_MAP) + if (t->base.Target == GL_TEXTURE_CUBE_MAP) t->format |= R300_TX_FORMAT_CUBIC_MAP; - if (!t->image_override) { - GLuint compressed = baseImage->IsCompressed ? baseImage->TexFormat->MesaFormat : 0; - - if (t->mt) { - if (t->mt->firstLevel != firstLevel || - t->mt->lastLevel != lastLevel || - t->mt->width0 != baseImage->Width || - t->mt->height0 != baseImage->Height || - t->mt->depth0 != baseImage->Depth || - t->mt->bpp != texelBytes || - t->mt->tilebits != t->tile_bits || - t->mt->compressed != compressed) { - r300_miptree_destroy(t->mt); - t->mt = 0; - } - } + t->size = (((firstImage->Width - 1) << R300_TX_WIDTHMASK_SHIFT) + | ((firstImage->Height - 1) << R300_TX_HEIGHTMASK_SHIFT)) + | ((t->mt->lastLevel - t->mt->firstLevel) << R300_TX_MAX_MIP_LEVEL_SHIFT); - if (!t->mt) { - t->mt = r300_miptree_create(rmesa, t, tObj->Target, - firstLevel, lastLevel, - baseImage->Width, baseImage->Height, baseImage->Depth, - texelBytes, t->tile_bits, compressed); - memset(t->dirty_images, 0xff, sizeof(t->dirty_images)); - } - } - - t->size = (((tObj->Image[0][firstLevel]->Width - 1) << R300_TX_WIDTHMASK_SHIFT) - | ((tObj->Image[0][firstLevel]->Height - 1) << R300_TX_HEIGHTMASK_SHIFT)) - | ((lastLevel - firstLevel) << R300_TX_MAX_MIP_LEVEL_SHIFT); - - if (tObj->Target == GL_TEXTURE_RECTANGLE_NV) { - unsigned int align = (64 / texelBytes) - 1; + if (t->base.Target == GL_TEXTURE_RECTANGLE_NV) { + unsigned int align = (64 / t->mt->bpp) - 1; t->size |= R300_TX_SIZE_TXPITCH_EN; if (!t->image_override) - t->pitch_reg = (((tObj->Image[0][firstLevel]->Width) + align) & ~align) - 1; + t->pitch_reg = ((firstImage->Width + align) & ~align) - 1; } if (rmesa->radeon.radeonScreen->chip_family >= CHIP_FAMILY_RV515) { - if (tObj->Image[0][firstLevel]->Width > 2048) + if (firstImage->Width > 2048) t->pitch_reg |= R500_TXWIDTH_BIT11; - if (tObj->Image[0][firstLevel]->Height > 2048) + if (firstImage->Height > 2048) t->pitch_reg |= R500_TXHEIGHT_BIT11; } } -/* ================================================================ - * Texture unit state management - */ -static GLboolean r300EnableTexture2D(GLcontext * ctx, int unit) +static void copy_rows(void* dst, GLuint dststride, const void* src, GLuint srcstride, + GLuint numrows, GLuint rowsize) { - r300ContextPtr rmesa = R300_CONTEXT(ctx); - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; - struct gl_texture_object *tObj = texUnit->_Current; - r300TexObjPtr t = r300_tex_obj(tObj); + assert(rowsize <= dststride); + assert(rowsize <= srcstride); - ASSERT(tObj->Target == GL_TEXTURE_2D || tObj->Target == GL_TEXTURE_1D); - - if (!t->mt || t->dirty_images[0]) { - R300_FIREVERTICES(rmesa); - - r300SetTexImages(rmesa, tObj); - r300UploadTexImages(rmesa, t, 0); + if (rowsize == srcstride && rowsize == dststride) { + memcpy(dst, src, numrows*rowsize); + } else { + GLuint i; + for(i = 0; i < numrows; ++i) { + memcpy(dst, src, rowsize); + dst += dststride; + src += srcstride; + } } - - return GL_TRUE; } -static GLboolean r300EnableTexture3D(GLcontext * ctx, int unit) + +/** + * Ensure that the given image is stored in the given miptree from now on. + */ +static void migrate_image_to_miptree(r300_mipmap_tree *mt, r300_texture_image *image, int face, int level) { - r300ContextPtr rmesa = R300_CONTEXT(ctx); - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; - struct gl_texture_object *tObj = texUnit->_Current; - r300TexObjPtr t = r300_tex_obj(tObj); + r300_mipmap_level *dstlvl = &mt->levels[level - mt->firstLevel]; + unsigned char *dest; - ASSERT(tObj->Target == GL_TEXTURE_3D); + assert(image->mt != mt); + assert(dstlvl->width == image->base.Width); + assert(dstlvl->height == image->base.Height); + assert(dstlvl->depth == image->base.Depth); - /* r300 does not support mipmaps for 3D textures. */ - if ((tObj->MinFilter != GL_NEAREST) && (tObj->MinFilter != GL_LINEAR)) { - return GL_FALSE; - } + dri_bo_map(mt->bo, GL_TRUE); + dest = mt->bo->virtual + dstlvl->faces[face].offset; - if (!t->mt || t->dirty_images[0]) { - R300_FIREVERTICES(rmesa); - r300SetTexImages(rmesa, tObj); - r300UploadTexImages(rmesa, t, 0); - } + if (image->mt) { + /* Format etc. should match, so we really just need a memcpy(). + * In fact, that memcpy() could be done by the hardware in many + * cases, provided that we have a proper memory manager. + */ + r300_mipmap_level *srclvl = &image->mt->levels[image->mtlevel]; - return GL_TRUE; -} + assert(srclvl->size == dstlvl->size); + assert(srclvl->rowstride == dstlvl->rowstride); -static GLboolean r300EnableTextureCube(GLcontext * ctx, int unit) -{ - r300ContextPtr rmesa = R300_CONTEXT(ctx); - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; - struct gl_texture_object *tObj = texUnit->_Current; - r300TexObjPtr t = r300_tex_obj(tObj); - GLuint face; - - ASSERT(tObj->Target == GL_TEXTURE_CUBE_MAP); - - if (!t->mt || - t->dirty_images[0] || t->dirty_images[1] || - t->dirty_images[2] || t->dirty_images[3] || - t->dirty_images[4] || t->dirty_images[5]) { - /* flush */ - R300_FIREVERTICES(rmesa); - /* layout memory space, once for all faces */ - r300SetTexImages(rmesa, tObj); - } + dri_bo_map(image->mt->bo, GL_FALSE); + memcpy(dest, + image->mt->bo->virtual + srclvl->faces[face].offset, + dstlvl->size); + dri_bo_unmap(image->mt->bo); - /* upload (per face) */ - for (face = 0; face < 6; face++) { - if (t->dirty_images[face]) { - r300UploadTexImages(rmesa, t, face); - } + r300_miptree_unreference(image->mt); + } else { + uint srcrowstride = image->base.Width * image->base.TexFormat->TexelBytes; + + if (mt->tilebits) + WARN_ONCE("%s: tiling not supported yet", __FUNCTION__); + + copy_rows(dest, dstlvl->rowstride, image->base.Data, srcrowstride, + image->base.Height * image->base.Depth, srcrowstride); + + _mesa_free_texmemory(image->base.Data); + image->base.Data = 0; } - return GL_TRUE; + dri_bo_unmap(mt->bo); + + image->mt = mt; + image->mtface = face; + image->mtlevel = level; + r300_miptree_reference(image->mt); } -static GLboolean r300EnableTextureRect(GLcontext * ctx, int unit) + +/** + * Ensure the given texture is ready for rendering. + * + * Mostly this means populating the texture object's mipmap tree. + */ +static GLboolean r300_validate_texture(GLcontext * ctx, struct gl_texture_object *texObj) { r300ContextPtr rmesa = R300_CONTEXT(ctx); - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; - struct gl_texture_object *tObj = texUnit->_Current; - r300TexObjPtr t = r300_tex_obj(tObj); + r300TexObj *t = r300_tex_obj(texObj); + r300_texture_image *baseimage = get_r300_texture_image(texObj->Image[0][texObj->BaseLevel]); + int face, level; + + if (t->validated) + return GL_TRUE; + + if (RADEON_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, "%s: Validating texture %p now\n", __FUNCTION__, texObj); + + if (baseimage->base.Border > 0) + return GL_FALSE; - ASSERT(tObj->Target == GL_TEXTURE_RECTANGLE_NV); + /* Ensure a matching miptree exists. + * + * Differing mipmap trees can result when the app uses TexImage to + * change texture dimensions. + * + * Prefer to use base image's miptree if it + * exists, since that most likely contains more valid data (remember + * that the base level is usually significantly larger than the rest + * of the miptree, so cubemaps are the only possible exception). + */ + if (baseimage->mt && + baseimage->mt != t->mt && + r300_miptree_matches_texture(baseimage->mt, &t->base)) { + r300_miptree_unreference(t->mt); + t->mt = baseimage->mt; + r300_miptree_reference(t->mt); + } else if (t->mt && !r300_miptree_matches_texture(t->mt, &t->base)) { + r300_miptree_unreference(t->mt); + t->mt = 0; + } - if (!t->mt || t->dirty_images[0]) { - R300_FIREVERTICES(rmesa); + if (!t->mt) { + if (RADEON_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, " Allocate new miptree\n"); + r300_try_alloc_miptree(rmesa, t, &baseimage->base, 0, texObj->BaseLevel); + if (!t->mt) { + _mesa_problem(ctx, "r300_validate_texture failed to alloc miptree"); + return GL_FALSE; + } + } + + /* Ensure all images are stored in the single main miptree */ + for(face = 0; face < t->mt->faces; ++face) { + for(level = t->mt->firstLevel; level <= t->mt->lastLevel; ++level) { + r300_texture_image *image = get_r300_texture_image(texObj->Image[face][level]); + if (RADEON_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, " face %i, level %i... ", face, level); + if (t->mt == image->mt) { + if (RADEON_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, "OK\n"); + continue; + } - r300SetTexImages(rmesa, tObj); - r300UploadTexImages(rmesa, t, 0); + if (RADEON_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, "migrating\n"); + migrate_image_to_miptree(t->mt, image, face, level); + } } + /* Configure the hardware registers (more precisely, the cached version + * of the hardware registers). */ + setup_hardware_state(rmesa, t); + + t->validated = GL_TRUE; return GL_TRUE; } -static GLboolean r300UpdateTexture(GLcontext * ctx, int unit) -{ - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; - struct gl_texture_object *tObj = texUnit->_Current; - r300TexObjPtr t = r300_tex_obj(tObj); - /* Fallback if there's a texture border */ - if (tObj->Image[0][tObj->BaseLevel]->Border > 0) - return GL_FALSE; +/** + * Ensure all enabled and complete textures are uploaded. + */ +void r300ValidateTextures(GLcontext * ctx) +{ + int i; - /* Fallback if memory upload didn't work */ - if (!t->mt) - return GL_FALSE; + for (i = 0; i < ctx->Const.MaxTextureImageUnits; ++i) { + if (!ctx->Texture.Unit[i]._ReallyEnabled) + continue; - return GL_TRUE; + if (!r300_validate_texture(ctx, ctx->Texture.Unit[i]._Current)) { + _mesa_warning(ctx, + "failed to validate texture for unit %d.\n", + i); + } + } } void r300SetTexOffset(__DRIcontext * pDRICtx, GLint texname, @@ -481,39 +455,3 @@ void r300SetTexOffset(__DRIcontext * pDRICtx, GLint texname, t->pitch_reg |= pitch_val; } - -static GLboolean r300UpdateTextureUnit(GLcontext * ctx, int unit) -{ - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; - - if (texUnit->_ReallyEnabled & (TEXTURE_RECT_BIT)) { - return (r300EnableTextureRect(ctx, unit) && - r300UpdateTexture(ctx, unit)); - } else if (texUnit->_ReallyEnabled & (TEXTURE_1D_BIT | TEXTURE_2D_BIT)) { - return (r300EnableTexture2D(ctx, unit) && - r300UpdateTexture(ctx, unit)); - } else if (texUnit->_ReallyEnabled & (TEXTURE_3D_BIT)) { - return (r300EnableTexture3D(ctx, unit) && - r300UpdateTexture(ctx, unit)); - } else if (texUnit->_ReallyEnabled & (TEXTURE_CUBE_BIT)) { - return (r300EnableTextureCube(ctx, unit) && - r300UpdateTexture(ctx, unit)); - } else if (texUnit->_ReallyEnabled) { - return GL_FALSE; - } else { - return GL_TRUE; - } -} - -void r300UpdateTextureState(GLcontext * ctx) -{ - int i; - - for (i = 0; i < 8; i++) { - if (!r300UpdateTextureUnit(ctx, i)) { - _mesa_warning(ctx, - "failed to update texture state for unit %d.\n", - i); - } - } -} diff --git a/src/mesa/drivers/dri/r300/radeon_span.c b/src/mesa/drivers/dri/r300/radeon_span.c index 62def66b94..e617faf6d2 100644 --- a/src/mesa/drivers/dri/r300/radeon_span.c +++ b/src/mesa/drivers/dri/r300/radeon_span.c @@ -299,6 +299,11 @@ static void radeonSpanRenderStart(GLcontext * ctx) RADEON_FIREVERTICES(rmesa); #endif + for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) { + if (ctx->Texture.Unit[i]._ReallyEnabled) + ctx->Driver.MapTexture(ctx, ctx->Texture.Unit[i]._Current); + } + /* color draw buffers */ for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) map_buffer(ctx->DrawBuffer->_ColorDrawBuffers[i], GL_TRUE); @@ -326,6 +331,11 @@ static void radeonSpanRenderFinish(GLcontext * ctx) _swrast_flush(ctx); UNLOCK_HARDWARE(rmesa); + for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) { + if (ctx->Texture.Unit[i]._ReallyEnabled) + ctx->Driver.UnmapTexture(ctx, ctx->Texture.Unit[i]._Current); + } + /* color draw buffers */ for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) unmap_buffer(ctx->DrawBuffer->_ColorDrawBuffers[i]); |