diff options
Diffstat (limited to 'xc/lib/GL/mesa/src/drv/r200/r200_texmem.c')
-rw-r--r-- | xc/lib/GL/mesa/src/drv/r200/r200_texmem.c | 809 |
1 files changed, 809 insertions, 0 deletions
diff --git a/xc/lib/GL/mesa/src/drv/r200/r200_texmem.c b/xc/lib/GL/mesa/src/drv/r200/r200_texmem.c new file mode 100644 index 000000000..fe584c4c5 --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/r200/r200_texmem.c @@ -0,0 +1,809 @@ +/* $XFree86$ */ +/************************************************************************** + +Copyright (C) Tungsten Graphics 2002. All Rights Reserved. +The Weather Channel, Inc. funded Tungsten Graphics to develop the +initial release of the Radeon 8500 driver under the XFree86 +license. This notice must be preserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation on the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR THEIR +SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#include "glheader.h" +#include "imports.h" +#include "context.h" +#include "colormac.h" +#include "mmath.h" +#include "macros.h" +#include "simple_list.h" +#include "radeon_reg.h" /* gets definition for usleep */ +#include "r200_context.h" +#include "r200_state.h" +#include "r200_ioctl.h" +#include "r200_swtcl.h" +#include "r200_tex.h" + +#include <unistd.h> /* for usleep() */ + + +/* Destroy hardware state associated with texture `t'. + */ +void r200DestroyTexObj( r200ContextPtr rmesa, r200TexObjPtr t ) +{ + if ( !t ) + return; + + if ( R200_DEBUG & DEBUG_TEXTURE ) { + fprintf( stderr, "%s( %p, %p )\n", __FUNCTION__, t, t->tObj ); + } + + if ( t->memBlock ) { + mmFreeMem( t->memBlock ); + t->memBlock = NULL; + } + + if ( t->tObj ) + t->tObj->DriverData = NULL; + + if ( rmesa ) { + if ( t == rmesa->state.texture.unit[0].texobj ) { + rmesa->state.texture.unit[0].texobj = NULL; + remove_from_list( &rmesa->hw.tex[0] ); + make_empty_list( &rmesa->hw.tex[0] ); + remove_from_list( &rmesa->hw.cube[0] ); + make_empty_list( &rmesa->hw.cube[0] ); + } + + if ( t == rmesa->state.texture.unit[1].texobj ) { + rmesa->state.texture.unit[1].texobj = NULL; + remove_from_list( &rmesa->hw.tex[1] ); + make_empty_list( &rmesa->hw.tex[1] ); + remove_from_list( &rmesa->hw.cube[1] ); + make_empty_list( &rmesa->hw.cube[1] ); + } + } + + remove_from_list( t ); + FREE( t ); +} + + +/* Keep track of swapped out texture objects. + */ +void r200SwapOutTexObj( r200ContextPtr rmesa, r200TexObjPtr t ) +{ + GLuint face; + + if ( R200_DEBUG & DEBUG_TEXTURE ) { + fprintf( stderr, "%s( %p, %p )\n", __FUNCTION__, t, t->tObj ); + } + + if (t->memBlock) { + mmFreeMem( t->memBlock ); + t->memBlock = NULL; + } + + if (!t->tObj) { + remove_from_list( t ); + FREE( t ); + } + else { + for (face = 0; face < 6; face++) + t->dirty_images[face] = ~0; + move_to_tail( &rmesa->texture.swapped, t ); + } +} + +/* Print out debugging information about texture LRU. + */ +void r200PrintLocalLRU( r200ContextPtr rmesa, int heap ) +{ + r200TexObjPtr t; + int sz = 1 << (rmesa->r200Screen->logTexGranularity[heap]); + + fprintf( stderr, "\nLocal LRU, heap %d:\n", heap ); + + foreach ( t, &rmesa->texture.objects[heap] ) { + if (!t->memBlock) + continue; + if (!t->tObj) { + fprintf( stderr, "Placeholder %d at 0x%x sz 0x%x\n", + t->memBlock->ofs / sz, + t->memBlock->ofs, + t->memBlock->size ); + } else { + fprintf( stderr, "Texture at 0x%x sz 0x%x\n", + t->memBlock->ofs, + t->memBlock->size ); + } + } + + fprintf( stderr, "\n" ); +} + +void r200PrintGlobalLRU( r200ContextPtr rmesa, int heap ) +{ + radeon_tex_region_t *list = rmesa->sarea->texList[heap]; + int i, j; + + fprintf( stderr, "\nGlobal LRU, heap %d list %p:\n", heap, list ); + + for ( i = 0, j = RADEON_NR_TEX_REGIONS ; i < RADEON_NR_TEX_REGIONS ; i++ ) { + fprintf( stderr, "list[%d] age %d next %d prev %d\n", + j, list[j].age, list[j].next, list[j].prev ); + j = list[j].next; + if ( j == RADEON_NR_TEX_REGIONS ) break; + } + + if ( j != RADEON_NR_TEX_REGIONS ) { + fprintf( stderr, "Loop detected in global LRU\n" ); + for ( i = 0 ; i < RADEON_NR_TEX_REGIONS ; i++ ) { + fprintf( stderr, "list[%d] age %d next %d prev %d\n", + i, list[i].age, list[i].next, list[i].prev ); + } + } + + fprintf( stderr, "\n" ); +} + +/* Reset the global texture LRU. + */ +static void r200ResetGlobalLRU( r200ContextPtr rmesa, int heap ) +{ + radeon_tex_region_t *list = rmesa->sarea->texList[heap]; + int sz = 1 << rmesa->r200Screen->logTexGranularity[heap]; + int i; + + /* + * (Re)initialize the global circular LRU list. The last element in + * the array (RADEON_NR_TEX_REGIONS) is the sentinal. Keeping it at + * the end of the array allows it to be addressed rationally when + * looking up objects at a particular location in texture memory. + */ + for ( i = 0 ; (i+1) * sz <= rmesa->r200Screen->texSize[heap] ; i++ ) { + list[i].prev = i-1; + list[i].next = i+1; + list[i].age = 0; + } + + i--; + list[0].prev = RADEON_NR_TEX_REGIONS; + list[i].prev = i-1; + list[i].next = RADEON_NR_TEX_REGIONS; + list[RADEON_NR_TEX_REGIONS].prev = i; + list[RADEON_NR_TEX_REGIONS].next = 0; + rmesa->sarea->texAge[heap] = 0; +} + +/* Update the local and glock texture LRUs. + */ +void r200UpdateTexLRU(r200ContextPtr rmesa, r200TexObjPtr t ) +{ + int heap = t->heap; + radeon_tex_region_t *list = rmesa->sarea->texList[heap]; + int sz = rmesa->r200Screen->logTexGranularity[heap]; + int i, start, end; + + rmesa->texture.age[heap] = ++rmesa->sarea->texAge[heap]; + + if ( !t->memBlock ) + return; + + start = t->memBlock->ofs >> sz; + end = (t->memBlock->ofs + t->memBlock->size-1) >> sz; + + /* Update our local LRU */ + move_to_head( &rmesa->texture.objects[heap], t ); + + /* Update the global LRU */ + for ( i = start ; i <= end ; i++ ) { + list[i].in_use = 1; + list[i].age = rmesa->texture.age[heap]; + + /* remove_from_list(i) */ + list[(CARD32)list[i].next].prev = list[i].prev; + list[(CARD32)list[i].prev].next = list[i].next; + + /* insert_at_head(list, i) */ + list[i].prev = RADEON_NR_TEX_REGIONS; + list[i].next = list[RADEON_NR_TEX_REGIONS].next; + list[(CARD32)list[RADEON_NR_TEX_REGIONS].next].prev = i; + list[RADEON_NR_TEX_REGIONS].next = i; + } + + if ( 0 ) { + r200PrintGlobalLRU( rmesa, t->heap ); + r200PrintLocalLRU( rmesa, t->heap ); + } +} + +/* Update our notion of what textures have been changed since we last + * held the lock. This pertains to both our local textures and the + * textures belonging to other clients. Keep track of other client's + * textures by pushing a placeholder texture onto the LRU list -- these + * are denoted by (tObj == NULL). + */ +static void r200TexturesGone( r200ContextPtr rmesa, int heap, + int offset, int size, int in_use ) +{ + r200TexObjPtr t, tmp; + + foreach_s ( t, tmp, &rmesa->texture.objects[heap] ) { + if ( !t->memBlock || + t->memBlock->ofs >= offset + size || + t->memBlock->ofs + t->memBlock->size <= offset ) + continue; + + /* It overlaps - kick it out. Need to hold onto the currently + * bound objects, however. + */ + r200SwapOutTexObj( rmesa, t ); + } + + if ( in_use ) { + t = (r200TexObjPtr) CALLOC( sizeof(*t) ); + if ( !t ) return; + + t->memBlock = mmAllocMem( rmesa->texture.heap[heap], size, 0, offset ); + if ( !t->memBlock ) { + fprintf( stderr, "Couldn't alloc placeholder sz %x ofs %x\n", + (int)size, (int)offset ); + mmDumpMemInfo( rmesa->texture.heap[heap] ); + return; + } + insert_at_head( &rmesa->texture.objects[heap], t ); + } +} + +/* Update our client's shared texture state. If another client has + * modified a region in which we have textures, then we need to figure + * out which of our textures has been removed, and update our global + * LRU. + */ +void r200AgeTextures( r200ContextPtr rmesa, int heap ) +{ + RADEONSAREAPrivPtr sarea = rmesa->sarea; + + fprintf(stderr, "%s %d\n", __FUNCTION__, heap); + + if ( sarea->texAge[heap] != rmesa->texture.age[heap] ) { + int sz = 1 << rmesa->r200Screen->logTexGranularity[heap]; + int nr = 0; + int idx; + + for ( idx = sarea->texList[heap][RADEON_NR_TEX_REGIONS].prev ; + idx != RADEON_NR_TEX_REGIONS && nr < RADEON_NR_TEX_REGIONS ; + idx = sarea->texList[heap][idx].prev, nr++ ) + { + /* If switching texturing schemes, then the SAREA might not + * have been properly cleared, so we need to reset the + * global texture LRU. + */ + if ( idx * sz > rmesa->r200Screen->texSize[heap] ) { + nr = RADEON_NR_TEX_REGIONS; + break; + } + + if ( sarea->texList[heap][idx].age > rmesa->texture.age[heap] ) { + r200TexturesGone( rmesa, heap, idx * sz, sz, + sarea->texList[heap][idx].in_use ); + } + } + + if ( nr == RADEON_NR_TEX_REGIONS ) { + r200TexturesGone( rmesa, heap, 0, + rmesa->r200Screen->texSize[heap], 0 ); + r200ResetGlobalLRU( rmesa, heap ); + } + + rmesa->texture.age[heap] = sarea->texAge[heap]; + } +} + + +/* ------------------------------------------------------------ + * Texture image conversions + */ + + +static void r200UploadAGPClientSubImage( r200ContextPtr rmesa, + r200TexObjPtr t, + struct gl_texture_image *texImage, + GLint hwlevel, + GLint x, GLint y, + GLint width, GLint height ) +{ + const struct gl_texture_format *texFormat = texImage->TexFormat; + GLuint srcPitch, dstPitch; + int blit_format; + int srcOffset; + + /* + * XXX it appears that we always upload the full image, not a subimage. + * I.e. x==0, y==0, width=texWidth, height=texWidth. If this is ever + * changed, the src pitch will have to change. + */ + switch ( texFormat->TexelBytes ) { + case 1: + blit_format = R200_CP_COLOR_FORMAT_CI8; + srcPitch = t->image[0][0].width * texFormat->TexelBytes; + dstPitch = t->image[0][0].width * texFormat->TexelBytes; + break; + case 2: + blit_format = R200_CP_COLOR_FORMAT_RGB565; + srcPitch = t->image[0][0].width * texFormat->TexelBytes; + dstPitch = t->image[0][0].width * texFormat->TexelBytes; + break; + case 4: + blit_format = R200_CP_COLOR_FORMAT_ARGB8888; + srcPitch = t->image[0][0].width * texFormat->TexelBytes; + dstPitch = t->image[0][0].width * texFormat->TexelBytes; + break; + default: + return; + } + + t->image[0][hwlevel].data = texImage->Data; + srcOffset = r200AgpOffsetFromVirtual( rmesa, texImage->Data ); + + assert( srcOffset != ~0 ); + + /* Don't currently need to cope with small pitches? + */ + width = texImage->Width; + height = texImage->Height; + + r200EmitWait( rmesa, RADEON_WAIT_3D ); + + r200EmitBlit( rmesa, blit_format, + srcPitch, + srcOffset, + dstPitch, + t->bufAddr, + x, + y, + t->image[0][hwlevel].x + x, + t->image[0][hwlevel].y + y, + width, + height ); + + r200EmitWait( rmesa, RADEON_WAIT_2D ); +} + +static void r200UploadRectSubImage( r200ContextPtr rmesa, + r200TexObjPtr t, + struct gl_texture_image *texImage, + GLint x, GLint y, + GLint width, GLint height ) +{ + const struct gl_texture_format *texFormat = texImage->TexFormat; + int blit_format, dstPitch, done; + + switch ( texFormat->TexelBytes ) { + case 1: + blit_format = R200_CP_COLOR_FORMAT_CI8; + break; + case 2: + blit_format = R200_CP_COLOR_FORMAT_RGB565; + break; + case 4: + blit_format = R200_CP_COLOR_FORMAT_ARGB8888; + break; + default: + return; + } + + t->image[0][0].data = texImage->Data; + + /* Currently don't need to cope with small pitches. + */ + width = texImage->Width; + height = texImage->Height; + dstPitch = t->pp_txpitch + 32; + + if (rmesa->prefer_agp_client_texturing && texImage->IsClientData) { + /* In this case, could also use agp texturing. This is + * currently disabled, but has been tested & works. + */ + t->pp_txoffset = r200AgpOffsetFromVirtual( rmesa, texImage->Data ); + t->pp_txpitch = texImage->RowStride * texFormat->TexelBytes - 32; + + if (R200_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, + "Using agp texturing for rectangular client texture\n"); + + /* Release FB memory allocated for this image: + */ + if ( t->memBlock ) { + mmFreeMem( t->memBlock ); + t->memBlock = NULL; + } + + } + else if (texImage->IsClientData) { + /* Data already in agp memory, with usable pitch. + */ + GLuint srcPitch; + srcPitch = texImage->RowStride * texFormat->TexelBytes; + r200EmitBlit( rmesa, + blit_format, + srcPitch, + r200AgpOffsetFromVirtual( rmesa, texImage->Data ), + dstPitch, t->bufAddr, + 0, 0, + 0, 0, + width, height ); + } + else { + /* Data not in agp memory, or bad pitch. + */ + for (done = 0; done < height ; ) { + struct r200_dma_region region; + int lines = MIN2( height - done, RADEON_BUFFER_SIZE / dstPitch ); + int src_pitch; + char *tex; + + src_pitch = texImage->RowStride * texFormat->TexelBytes; + + tex = (char *)texImage->Data + done * src_pitch; + + memset(®ion, 0, sizeof(region)); + r200AllocDmaRegion( rmesa, ®ion, lines * dstPitch, 64 ); + + /* Copy texdata to dma: + */ + if (0) + fprintf(stderr, "%s: src_pitch %d dst_pitch %d\n", + __FUNCTION__, src_pitch, dstPitch); + + if (src_pitch == dstPitch) { + memcpy( region.address, tex, lines * src_pitch ); + } + else { + char *buf = region.address; + int i; + for (i = 0 ; i < lines ; i++) { + memcpy( buf, tex, src_pitch ); + buf += dstPitch; + tex += src_pitch; + } + } + + r200EmitWait( rmesa, RADEON_WAIT_3D ); + + /* Blit to framebuffer + */ + r200EmitBlit( rmesa, + blit_format, + dstPitch, GET_START( ®ion ), + dstPitch, t->bufAddr, + 0, 0, + 0, done, + width, lines ); + + r200EmitWait( rmesa, RADEON_WAIT_2D ); + + r200ReleaseDmaRegion( rmesa, ®ion, __FUNCTION__ ); + done += lines; + } + } +} + + +/* Upload the texture image associated with texture `t' at level `level' + * at the address relative to `start'. + */ +static void r200UploadSubImage( r200ContextPtr rmesa, + r200TexObjPtr t, + GLint hwlevel, + GLint x, GLint y, GLint width, GLint height, + GLuint face ) +{ + struct gl_texture_image *texImage = NULL; + const struct gl_texture_format *texFormat; + GLint texelsPerDword = 0; + GLuint format, pitch, offset; + GLint imageWidth, imageHeight; + GLint ret; + drmRadeonTexture tex; + drmRadeonTexImage tmp; + int level = hwlevel + t->firstLevel; + + if ( R200_DEBUG & DEBUG_TEXTURE ) { + fprintf( stderr, "%s level %d %dx%d\n", __FUNCTION__, + level, width, height); + } + + ASSERT(face < 6); + + /* Ensure we have a valid texture to upload */ + if ( ( hwlevel < 0 ) || ( hwlevel >= RADEON_MAX_TEXTURE_LEVELS ) ) { + _mesa_problem(NULL, "bad texture level in r200UploadSubimage"); + return; + } + + switch (face) { + case 0: + texImage = t->tObj->Image[level]; + break; + case 1: + texImage = t->tObj->NegX[level]; + break; + case 2: + texImage = t->tObj->PosY[level]; + break; + case 3: + texImage = t->tObj->NegY[level]; + break; + case 4: + texImage = t->tObj->PosZ[level]; + break; + case 5: + texImage = t->tObj->NegZ[level]; + break; + } + + if ( !texImage ) { + if ( R200_DEBUG & DEBUG_TEXTURE ) + fprintf( stderr, "%s: texImage %d is NULL!\n", __FUNCTION__, level ); + return; + } + if ( !texImage->Data ) { + if ( R200_DEBUG & DEBUG_TEXTURE ) + fprintf( stderr, "%s: image data is NULL!\n", __FUNCTION__ ); + return; + } + + + if (t->tObj->Target == GL_TEXTURE_RECTANGLE_NV) { + assert(level == 0); + assert(hwlevel == 0); + if ( R200_DEBUG & DEBUG_TEXTURE ) + fprintf( stderr, "%s: image data is rectangular\n", __FUNCTION__); + r200UploadRectSubImage( rmesa, t, texImage, x, y, width, height ); + return; + } + else if (texImage->IsClientData) { + if ( R200_DEBUG & DEBUG_TEXTURE ) + fprintf( stderr, "%s: image data is in agp client storage\n", + __FUNCTION__); + r200UploadAGPClientSubImage( rmesa, t, texImage, hwlevel, + x, y, width, height ); + return; + } + else if ( R200_DEBUG & DEBUG_TEXTURE ) + fprintf( stderr, "%s: image data is in normal memory\n", + __FUNCTION__); + + + texFormat = texImage->TexFormat; + + switch ( texFormat->TexelBytes ) { + case 1: + texelsPerDword = 4; + break; + case 2: + texelsPerDword = 2; + break; + case 4: + texelsPerDword = 1; + break; + } + + format = t->pp_txformat & R200_TXFORMAT_FORMAT_MASK; + + imageWidth = texImage->Width; + imageHeight = texImage->Height; + + offset = t->bufAddr; + + if (texFormat->TexelBytes == 0) + pitch = (t->image[face][0].width * 1) / 64; + else + pitch = (t->image[face][0].width * texFormat->TexelBytes) / 64; + + + if ( R200_DEBUG & (DEBUG_TEXTURE|DEBUG_IOCTL) ) + { + GLint imageX = 0; + GLint imageY = 0; + GLint blitX = t->image[face][hwlevel].x; + GLint blitY = t->image[face][hwlevel].y; + GLint blitWidth = t->image[face][hwlevel].width; + GLint blitHeight = t->image[face][hwlevel].height; + fprintf( stderr, " upload image: %d,%d at %d,%d\n", + imageWidth, imageHeight, imageX, imageY ); + fprintf( stderr, " upload blit: %d,%d at %d,%d\n", + blitWidth, blitHeight, blitX, blitY ); + fprintf( stderr, " blit ofs: 0x%07x pitch: 0x%x " + "level: %d/%d format: %x\n", + (GLuint)offset, (GLuint)pitch, hwlevel, level, format ); + } + + t->image[face][hwlevel].data = texImage->Data; + + /* Init the DRM_RADEON_TEXTURE command / drmRadeonTexture struct. + * NOTE: we're always use a 1KB-wide blit and I8 texture format. + * We used to use 1, 2 and 4-byte texels and used to use the texture + * width to dictate the blit width - but that won't work for compressed + * textures. (Brian) + */ + tex.offset = offset; + tex.pitch = BLIT_WIDTH_BYTES / 64; + tex.format = R200_TXFORMAT_I8; /* any 1-byte texel format */ + if (texImage->TexFormat->TexelBytes) { + tex.width = imageWidth * texImage->TexFormat->TexelBytes; /* in bytes */ + tex.height = imageHeight; + } + else { + tex.width = imageWidth; /* compressed */ + tex.height = imageHeight; + if (tex.height < 4) + tex.height = 4; + } + tex.image = &tmp; + + /* copy (x,y,width,height,data) */ + memcpy( &tmp, &t->image[face][hwlevel], sizeof(drmRadeonTexImage) ); + + LOCK_HARDWARE( rmesa ); + do { + ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_TEXTURE, + &tex, sizeof(drmRadeonTexture) ); + if (ret) { + if (R200_DEBUG & DEBUG_IOCTL) + fprintf(stderr, "DRM_RADEON_TEXTURE: again!\n"); + usleep(1); + } + } while ( ret && errno == EAGAIN ); + + UNLOCK_HARDWARE( rmesa ); + + if ( ret ) { + fprintf( stderr, "DRM_R200_TEXTURE: return = %d\n", ret ); + fprintf( stderr, " offset=0x%08x pitch=0x%x format=%d\n", + offset, pitch, format ); + fprintf( stderr, " image width=%d height=%d\n", + imageWidth, imageHeight ); + fprintf( stderr, " blit width=%d height=%d data=%p\n", + t->image[face][hwlevel].width, t->image[face][hwlevel].height, + t->image[face][hwlevel].data ); + exit( 1 ); + } +} + + + +/* Upload the texture images associated with texture `t'. This might + * require removing our own and/or other client's texture objects to + * make room for these images. + */ +int r200UploadTexImages( r200ContextPtr rmesa, r200TexObjPtr t, GLuint face ) +{ + const int numLevels = t->lastLevel - t->firstLevel + 1; + int heap; + r200TexObjPtr t0 = rmesa->state.texture.unit[0].texobj; + r200TexObjPtr t1 = rmesa->state.texture.unit[1].texobj; + + if ( R200_DEBUG & (DEBUG_TEXTURE|DEBUG_IOCTL) ) { + fprintf( stderr, "%s( %p, %p ) sz=%d lvls=%d-%d\n", __FUNCTION__, + rmesa->glCtx, t->tObj, t->totalSize, + t->firstLevel, t->lastLevel ); + } + + if ( !t || t->totalSize == 0 ) + return 0; + + if (R200_DEBUG & DEBUG_SYNC) { + fprintf(stderr, "\nSyncing\n\n"); + R200_FIREVERTICES( rmesa ); + r200Finish( rmesa->glCtx ); + } + + LOCK_HARDWARE( rmesa ); + + /* Choose the heap appropriately */ + heap = t->heap = RADEON_CARD_HEAP; + + /* Do we need to eject LRU texture objects? */ + if ( !t->memBlock ) { + /* Allocate a memory block on a 1k boundary (1<<10 == 1024) */ + t->memBlock = mmAllocMem( rmesa->texture.heap[heap], + t->totalSize, 10, 0 ); + + + /* Kick out textures until the requested texture fits */ + while ( !t->memBlock ) { + if ( rmesa->texture.objects[heap].prev == t0 || + rmesa->texture.objects[heap].prev == t1 ) { + fprintf( stderr, + "r200UploadTexImages: ran into bound texture\n" ); + UNLOCK_HARDWARE( rmesa ); + return -1; + } + if ( rmesa->texture.objects[heap].prev == + &rmesa->texture.objects[heap] ) { + if ( rmesa->r200Screen->IsPCI ) { + fprintf( stderr, "r200UploadTexImages: upload texture " + "failure on local texture heaps, sz=%d\n", + t->totalSize ); + UNLOCK_HARDWARE( rmesa ); + return -1; + } else { + fprintf( stderr, "r200UploadTexImages: upload texture " + "failure on both local and AGP texture heaps, " + "sz=%d\n", + t->totalSize ); + UNLOCK_HARDWARE( rmesa ); + return -1; + } + } + + r200SwapOutTexObj( rmesa, rmesa->texture.objects[heap].prev ); + + t->memBlock = mmAllocMem( rmesa->texture.heap[heap], + t->totalSize, 12, 0 ); + } + + /* Set the base offset of the texture image */ + t->bufAddr = rmesa->r200Screen->texOffset[heap] + t->memBlock->ofs; + t->pp_txoffset = t->bufAddr; + + /* Mark this texobj as dirty on all units: + */ + t->dirty_state = TEX_ALL; + } + + /* Let the world know we've used this memory recently */ + r200UpdateTexLRU( rmesa, t ); + UNLOCK_HARDWARE( rmesa ); + + /* Upload any images that are new */ + if (t->dirty_images[face]) { + int hwlevel; + for ( hwlevel = 0 ; hwlevel < numLevels ; hwlevel++ ) { + if ( t->dirty_images[face] & (1 << (hwlevel+t->firstLevel)) ) { + r200UploadSubImage( rmesa, t, hwlevel, + 0, 0, + t->image[face][hwlevel].width, + t->image[face][hwlevel].height, face ); + } + } + t->dirty_images[face] = 0; + } + + + if (R200_DEBUG & DEBUG_SYNC) { + fprintf(stderr, "\nSyncing\n\n"); + r200Finish( rmesa->glCtx ); + } + + return 0; +} |