static void radeonTexSubImage2D( 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 ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); radeonTexObjPtr t = (radeonTexObjPtr) texObj->DriverData; /* fprintf(stderr, "%s\n", __FUNCTION__); */ assert( t ); /* this _should_ be true */ if ( t ) { radeonSwapOutTexObj( rmesa, t ); } else { t = radeonAllocTexObj(texObj); if (!t) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D"); return; } texObj->DriverData = t; } _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width, height, format, type, pixels, packing, texObj, texImage); t->dirty_images |= (1 << level); }
static void radeonTexImage2D( 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 ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); radeonTexObjPtr t = (radeonTexObjPtr)texObj->DriverData; /* fprintf(stderr, "%s\n", __FUNCTION__); */ if ( t ) { radeonSwapOutTexObj( rmesa, t ); } else { t = radeonAllocTexObj( texObj ); if (!t) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D"); return; } texObj->DriverData = t; } /* Note, this will call radeonChooseTextureFormat */ _mesa_store_teximage2d(ctx, target, level, internalFormat, width, height, border, format, type, pixels, &ctx->Unpack, texObj, texImage); t->dirty_images |= (1 << level); }
/** * Texture space has been invalidated. * * \param rmesa Radeon context. * \param heap texture heap number. * * Swaps out every texture in the specified heap. */ void radeonAgeTextures( radeonContextPtr rmesa, int heap ) { radeonTexObjPtr t, tmp; foreach_s ( t, tmp, &rmesa->texture.objects[heap] ) radeonSwapOutTexObj( rmesa, t ); }
static void radeonTexParameter( GLcontext *ctx, GLenum target, struct gl_texture_object *texObj, GLenum pname, const GLfloat *params ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); radeonTexObjPtr t = (radeonTexObjPtr) texObj->DriverData; if ( RADEON_DEBUG & (DEBUG_STATE|DEBUG_TEXTURE) ) { fprintf( stderr, "%s( %s )\n", __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) ); } if ( ( target != GL_TEXTURE_2D ) && ( target != GL_TEXTURE_1D ) ) return; switch ( pname ) { case GL_TEXTURE_MIN_FILTER: case GL_TEXTURE_MAG_FILTER: case GL_TEXTURE_MAX_ANISOTROPY_EXT: radeonSetTexMaxAnisotropy( t, texObj->MaxAnisotropy ); radeonSetTexFilter( t, texObj->MinFilter, texObj->MagFilter ); break; case GL_TEXTURE_WRAP_S: case GL_TEXTURE_WRAP_T: radeonSetTexWrap( t, texObj->WrapS, texObj->WrapT ); break; case GL_TEXTURE_BORDER_COLOR: radeonSetTexBorderColor( t, texObj->BorderColor ); break; case GL_TEXTURE_BASE_LEVEL: case GL_TEXTURE_MAX_LEVEL: case GL_TEXTURE_MIN_LOD: case GL_TEXTURE_MAX_LOD: /* This isn't the most efficient solution but there doesn't appear to * be a nice alternative for Radeon. Since there's no LOD clamping, * we just have to rely on loading the right subset of mipmap levels * to simulate a clamped LOD. */ radeonSwapOutTexObj( rmesa, t ); break; default: return; } /* Mark this texobj as dirty (one bit per tex unit) */ t->dirty_state = TEX_ALL; }
/** * \brief Load a texture image. * * \param ctx GL context. * \param texObj texture object * \param target target texture. * \param level level of detail number. * \param internalFormat internal format. * \param width texture image width. * \param height texture image height. * \param border border width. * \param format pixel format. * \param type pixel data type. * \param pixels image data. * \param packing passed to _mesa_store_teximage2d() unchanged. * \param texImage passed to _mesa_store_teximage2d() unchanged. * * If there is a device specific texture object associated with the given * texture object then swaps that texture out. Calls _mesa_store_teximage2d() * with all other parameters unchanged. */ static void radeonTexImage2D( 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 ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); radeonTexObjPtr t = (radeonTexObjPtr)texObj->DriverData; if ( t ) radeonSwapOutTexObj( rmesa, t ); /* Note, this will call radeonChooseTextureFormat */ _mesa_store_teximage2d(ctx, target, level, internalFormat, width, height, border, format, type, pixels, &ctx->Unpack, texObj, texImage); }
/** * \brief Upload texture images. * * This might require removing our own and/or other client's texture objects to * make room for these images. * * \param rmesa Radeon context. * \param tObj texture object to upload. * * Sets the matching hardware texture format. Calculates which mipmap levels to * send, depending of the base image size, GL_TEXTURE_MIN_LOD, * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL and the * Radeon offset rules. Kicks out textures until the requested texture fits, * sets the texture hardware state and, while holding the hardware lock, * uploads any images that are new. */ static void radeonSetTexImages( radeonContextPtr rmesa, struct gl_texture_object *tObj ) { radeonTexObjPtr t = (radeonTexObjPtr)tObj->DriverData; const struct gl_texture_image *baseImage = tObj->Image[0][tObj->BaseLevel]; GLint totalSize; GLint texelsPerDword = 0, blitWidth = 0, blitPitch = 0; GLint x, y, width, height; GLint i; GLint firstLevel, lastLevel, numLevels; GLint log2Width, log2Height; GLuint txformat = 0; /* This code cannot be reached once we have lost focus */ assert(rmesa->radeonScreen->buffers); /* Set the hardware texture format */ switch (baseImage->TexFormat->MesaFormat) { case MESA_FORMAT_I8: txformat = RADEON_TXFORMAT_I8; texelsPerDword = 4; blitPitch = 64; break; case MESA_FORMAT_RGBA8888: txformat = RADEON_TXFORMAT_RGBA8888 | RADEON_TXFORMAT_ALPHA_IN_MAP; texelsPerDword = 1; blitPitch = 16; break; case MESA_FORMAT_RGB565: txformat = RADEON_TXFORMAT_RGB565; texelsPerDword = 2; blitPitch = 32; break; default: _mesa_problem(NULL, "unexpected texture format in radeonTexImage2D"); return; } t->pp_txformat &= ~(RADEON_TXFORMAT_FORMAT_MASK | RADEON_TXFORMAT_ALPHA_IN_MAP); t->pp_txformat |= txformat; /* Select the larger of the two widths for our global texture image * coordinate space. As the Radeon has very strict offset rules, we * can't upload mipmaps directly and have to reference their location * from the aligned start of the whole image. */ blitWidth = MAX2( baseImage->Width, blitPitch ); /* Calculate mipmap offsets and dimensions. */ totalSize = 0; x = 0; y = 0; /* Compute which mipmap levels we really want to send to the hardware. * This depends on the base image size, GL_TEXTURE_MIN_LOD, * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL. * Yes, this looks overly complicated, but it's all needed. */ firstLevel = tObj->BaseLevel + (GLint) (tObj->MinLod + 0.5); firstLevel = MAX2(firstLevel, tObj->BaseLevel); 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 */ /* save these values */ t->firstLevel = firstLevel; t->lastLevel = lastLevel; numLevels = lastLevel - firstLevel + 1; log2Width = tObj->Image[0][firstLevel]->WidthLog2; log2Height = tObj->Image[0][firstLevel]->HeightLog2; for ( i = 0 ; i < numLevels ; i++ ) { const struct gl_texture_image *texImage = tObj->Image[0][i + firstLevel]; if ( !texImage ) break; width = texImage->Width; height = texImage->Height; /* Texture images have a minimum pitch of 32 bytes (half of the * 64-byte minimum pitch for blits). For images that have a * width smaller than this, we must pad each texture image * scanline out to this amount. */ if ( width < blitPitch / 2 ) { width = blitPitch / 2; } totalSize += width * height * baseImage->TexFormat->TexelBytes; ASSERT( (totalSize & 31) == 0 ); while ( width < blitWidth && height > 1 ) { width *= 2; height /= 2; } ASSERT(i < RADEON_MAX_TEXTURE_LEVELS); t->image[i].x = x; t->image[i].y = y; t->image[i].width = width; t->image[i].height = height; /* While blits must have a pitch of at least 64 bytes, mipmaps * must be aligned on a 32-byte boundary (just like each texture * image scanline). */ if ( width >= blitWidth ) { y += height; } else { x += width; if ( x >= blitWidth ) { x = 0; y++; } } } /* Align the total size of texture memory block. */ t->totalSize = (totalSize + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK; /* Hardware state: */ t->pp_txfilter &= ~RADEON_MAX_MIP_LEVEL_MASK; t->pp_txfilter |= (numLevels - 1) << RADEON_MAX_MIP_LEVEL_SHIFT; t->pp_txformat &= ~(RADEON_TXFORMAT_WIDTH_MASK | RADEON_TXFORMAT_HEIGHT_MASK); t->pp_txformat |= ((log2Width << RADEON_TXFORMAT_WIDTH_SHIFT) | (log2Height << RADEON_TXFORMAT_HEIGHT_SHIFT)); t->dirty_state = TEX_ALL; /* Update the local texture LRU. */ move_to_head( &rmesa->texture.objects[0], t ); LOCK_HARDWARE( rmesa ); /* Kick out textures until the requested texture fits */ while ( !t->memBlock ) { t->memBlock = mmAllocMem( rmesa->texture.heap[0], t->totalSize, 12, 0); if (!t->memBlock) radeonSwapOutTexObj( rmesa, rmesa->texture.objects[0].prev ); } /* Set the base offset of the texture image */ t->bufAddr = rmesa->radeonScreen->texOffset[0] + t->memBlock->ofs; t->pp_txoffset = t->bufAddr; /* Upload any images that are new */ for ( i = 0 ; i < numLevels ; i++ ) { if ( t->dirty_images & (1 << i) ) { radeonUploadSubImage( rmesa, t, i, 0, 0, t->image[i].width, t->image[i].height ); } } rmesa->texture.age[0] = ++rmesa->sarea->texAge[0]; UNLOCK_HARDWARE( rmesa ); t->dirty_images = 0; }