summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolai Haehnle <nhaehnle@gmail.com>2008-08-19 22:02:41 +0200
committerNicolai Haehnle <nhaehnle@gmail.com>2008-09-28 18:02:39 +0200
commit857362ef14fc4f175a9d425a74f9ca2b691971d6 (patch)
treee5c523f81461786db7ccce7711ae740b9f041d52
parentb3153fc6f7823b434ab82faec4e966c3311f8ce8 (diff)
r300: Reasonably hacked up texture images
-rw-r--r--src/mesa/drivers/dri/r300/r300_context.h35
-rw-r--r--src/mesa/drivers/dri/r300/r300_mipmap_tree.c224
-rw-r--r--src/mesa/drivers/dri/r300/r300_mipmap_tree.h22
-rw-r--r--src/mesa/drivers/dri/r300/r300_state.c4
-rw-r--r--src/mesa/drivers/dri/r300/r300_tex.c498
-rw-r--r--src/mesa/drivers/dri/r300/r300_tex.h5
-rw-r--r--src/mesa/drivers/dri/r300/r300_texmem.c47
-rw-r--r--src/mesa/drivers/dri/r300/r300_texstate.c382
-rw-r--r--src/mesa/drivers/dri/r300/radeon_span.c10
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]);