summaryrefslogtreecommitdiff
path: root/src/mesa/drivers/dri/radeon/radeon_subset_tex.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/drivers/dri/radeon/radeon_subset_tex.c')
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_subset_tex.c1018
1 files changed, 1018 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/radeon/radeon_subset_tex.c b/src/mesa/drivers/dri/radeon/radeon_subset_tex.c
new file mode 100644
index 0000000000..e401779513
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_subset_tex.c
@@ -0,0 +1,1018 @@
+/**
+ * \file radeon_subset_tex.c
+ * \brief Texturing.
+ *
+ * \author Gareth Hughes <gareth@valinux.com>
+ * \author Brian Paul <brianp@valinux.com>
+ */
+
+/*
+ * Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+ * VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * 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.
+ */
+
+/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_tex.c,v 1.6 2002/09/16 18:05:20 eich Exp $ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "colormac.h"
+#include "context.h"
+#include "enums.h"
+#include "image.h"
+#include "simple_list.h"
+#include "texformat.h"
+#include "texstore.h"
+
+#include "radeon_context.h"
+#include "radeon_state.h"
+#include "radeon_ioctl.h"
+#include "radeon_subset.h"
+
+#include <errno.h>
+#include <stdio.h>
+
+
+/**
+ * \brief Destroy hardware state associated with a texture.
+ *
+ * \param rmesa Radeon context.
+ * \param t Radeon texture object to be destroyed.
+ *
+ * Frees the memory associated with the texture and if the texture is bound to
+ * a texture unit cleans the associated hardware state.
+ */
+void radeonDestroyTexObj( radeonContextPtr rmesa, radeonTexObjPtr t )
+{
+ 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( t );
+ FREE( t );
+}
+
+
+/**
+ * \brief Keep track of swapped out texture objects.
+ *
+ * \param rmesa Radeon context.
+ * \param t Radeon texture object.
+ *
+ * Frees the memory associated with the texture, marks all mipmap images in
+ * the texture as dirty and add it to the radeon_texture::swapped list.
+ */
+static void radeonSwapOutTexObj( radeonContextPtr rmesa, radeonTexObjPtr t )
+{
+ if ( t->memBlock ) {
+ mmFreeMem( t->memBlock );
+ t->memBlock = NULL;
+ }
+
+ t->dirty_images = ~0;
+ move_to_tail( &rmesa->texture.swapped, t );
+}
+
+
+/**
+ * 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 );
+}
+
+
+/***************************************************************/
+/** \name Texture image conversions
+ */
+/*@{*/
+
+/**
+ * \brief Upload texture image.
+ *
+ * \param rmesa Radeon context.
+ * \param t Radeon texture object.
+ * \param level level of the image to take the sub-image.
+ * \param x sub-image abscissa.
+ * \param y sub-image ordinate.
+ * \param width sub-image width.
+ * \param height sub-image height.
+ *
+ * Fills in a drmRadeonTexture and drmRadeonTexImage structures and uploads the
+ * texture via the DRM_RADEON_TEXTURE ioctl, aborting in case of failure.
+ */
+static void radeonUploadSubImage( radeonContextPtr rmesa,
+ radeonTexObjPtr t, GLint level,
+ GLint x, GLint y, GLint width, GLint height )
+{
+ struct gl_texture_image *texImage;
+ GLint ret;
+ drmRadeonTexture tex;
+ drmRadeonTexImage tmp;
+
+ level += t->firstLevel;
+ texImage = t->tObj->Image[level];
+
+ if ( !texImage || !texImage->Data )
+ return;
+
+ t->image[level].data = texImage->Data;
+
+ tex.offset = t->bufAddr;
+ tex.pitch = (t->image[0].width * texImage->TexFormat->TexelBytes) / 64;
+ tex.format = t->pp_txformat & RADEON_TXFORMAT_FORMAT_MASK;
+ tex.width = texImage->Width;
+ tex.height = texImage->Height;
+ tex.image = &tmp;
+
+ memcpy( &tmp, &t->image[level], sizeof(drmRadeonTexImage) );
+
+ do {
+ ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_TEXTURE,
+ &tex, sizeof(drmRadeonTexture) );
+ } while ( ret && errno == EAGAIN );
+
+ if ( ret ) {
+ UNLOCK_HARDWARE( rmesa );
+ fprintf( stderr, "DRM_RADEON_TEXTURE: return = %d\n", ret );
+ exit( 1 );
+ }
+}
+
+/**
+ * \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[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[firstLevel]->WidthLog2;
+ log2Height = tObj->Image[firstLevel]->HeightLog2;
+
+ for ( i = 0 ; i < numLevels ; i++ ) {
+ const struct gl_texture_image *texImage = tObj->Image[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;
+}
+
+/*@}*/
+
+
+/******************************************************************/
+/** \name Texture combine functions
+ */
+/*@{*/
+
+enum {
+ RADEON_DISABLE = 0, /**< \brief disabled */
+ RADEON_REPLACE = 1, /**< \brief replace function */
+ RADEON_MODULATE = 2, /**< \brief modulate function */
+ RADEON_DECAL = 3, /**< \brief decal function */
+ RADEON_BLEND = 4, /**< \brief blend function */
+ RADEON_MAX_COMBFUNC = 5 /**< \brief max number of combine functions */
+} ;
+
+
+/**
+ * \brief Color combine function hardware state table.
+ */
+static GLuint radeon_color_combine[][RADEON_MAX_COMBFUNC] =
+{
+ /* Unit 0:
+ */
+ {
+ /* Disable combiner stage
+ */
+ (RADEON_COLOR_ARG_A_ZERO |
+ RADEON_COLOR_ARG_B_ZERO |
+ RADEON_COLOR_ARG_C_CURRENT_COLOR |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_REPLACE = 0x00802800
+ */
+ (RADEON_COLOR_ARG_A_ZERO |
+ RADEON_COLOR_ARG_B_ZERO |
+ RADEON_COLOR_ARG_C_T0_COLOR |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_MODULATE = 0x00800142
+ */
+ (RADEON_COLOR_ARG_A_CURRENT_COLOR |
+ RADEON_COLOR_ARG_B_T0_COLOR |
+ RADEON_COLOR_ARG_C_ZERO |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_DECAL = 0x008c2d42
+ */
+ (RADEON_COLOR_ARG_A_CURRENT_COLOR |
+ RADEON_COLOR_ARG_B_T0_COLOR |
+ RADEON_COLOR_ARG_C_T0_ALPHA |
+ RADEON_BLEND_CTL_BLEND |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_BLEND = 0x008c2902
+ */
+ (RADEON_COLOR_ARG_A_CURRENT_COLOR |
+ RADEON_COLOR_ARG_B_TFACTOR_COLOR |
+ RADEON_COLOR_ARG_C_T0_COLOR |
+ RADEON_BLEND_CTL_BLEND |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+ },
+
+};
+
+/**
+ * \brief Alpha combine function hardware state table.
+ */
+static GLuint radeon_alpha_combine[][RADEON_MAX_COMBFUNC] =
+{
+ /* Unit 0:
+ */
+ {
+ /* Disable combiner stage
+ */
+ (RADEON_ALPHA_ARG_A_ZERO |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_ALPHA_ARG_C_CURRENT_ALPHA |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_REPLACE = 0x00800500
+ */
+ (RADEON_ALPHA_ARG_A_ZERO |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_ALPHA_ARG_C_T0_ALPHA |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_MODULATE = 0x00800051
+ */
+ (RADEON_ALPHA_ARG_A_CURRENT_ALPHA |
+ RADEON_ALPHA_ARG_B_T0_ALPHA |
+ RADEON_ALPHA_ARG_C_ZERO |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_DECAL = 0x00800100
+ */
+ (RADEON_ALPHA_ARG_A_ZERO |
+ RADEON_ALPHA_ARG_B_ZERO |
+ RADEON_ALPHA_ARG_C_CURRENT_ALPHA |
+ RADEON_BLEND_CTL_ADD |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ /* GL_BLEND = 0x00800051
+ */
+ (RADEON_ALPHA_ARG_A_CURRENT_ALPHA |
+ RADEON_ALPHA_ARG_B_TFACTOR_ALPHA |
+ RADEON_ALPHA_ARG_C_T0_ALPHA |
+ RADEON_BLEND_CTL_BLEND |
+ RADEON_SCALE_1X |
+ RADEON_CLAMP_TX),
+
+ },
+
+};
+
+/*@}*/
+
+
+/******************************************************************/
+/** \name Texture unit state management
+ */
+/*@{*/
+
+/**
+ * \brief Update the texture environment.
+ *
+ * \param ctx GL context
+ * \param unit texture unit to update.
+ *
+ * Sets the state of the RADEON_TEX_PP_TXCBLEND and RADEON_TEX_PP_TXABLEND
+ * registers using the ::radeon_color_combine and ::radeon_alpha_combine tables,
+ * and informs of the state change.
+ */
+static void radeonUpdateTextureEnv( GLcontext *ctx, int unit )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+ const struct gl_texture_object *tObj = texUnit->_Current;
+ const GLenum format = tObj->Image[tObj->BaseLevel]->Format;
+ GLuint color_combine = radeon_color_combine[unit][RADEON_DISABLE];
+ GLuint alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
+
+
+ /* Set the texture environment state. Isn't this nice and clean?
+ * The Radeon will automagically set the texture alpha to 0xff when
+ * the texture format does not include an alpha component. This
+ * reduces the amount of special-casing we have to do, alpha-only
+ * textures being a notable exception.
+ */
+ switch ( texUnit->EnvMode ) {
+ case GL_REPLACE:
+ switch ( format ) {
+ case GL_RGBA:
+ case GL_INTENSITY:
+ color_combine = radeon_color_combine[unit][RADEON_REPLACE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_REPLACE];
+ break;
+ case GL_RGB:
+ color_combine = radeon_color_combine[unit][RADEON_REPLACE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case GL_MODULATE:
+ switch ( format ) {
+ case GL_RGBA:
+ case GL_INTENSITY:
+ color_combine = radeon_color_combine[unit][RADEON_MODULATE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE];
+ break;
+ case GL_RGB:
+ color_combine = radeon_color_combine[unit][RADEON_MODULATE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case GL_DECAL:
+ switch ( format ) {
+ case GL_RGBA:
+ case GL_RGB:
+ color_combine = radeon_color_combine[unit][RADEON_DECAL];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
+ break;
+ case GL_INTENSITY:
+ color_combine = radeon_color_combine[unit][RADEON_DISABLE];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case GL_BLEND:
+ switch ( format ) {
+ case GL_RGBA:
+ case GL_RGB:
+ color_combine = radeon_color_combine[unit][RADEON_BLEND];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE];
+ break;
+ case GL_INTENSITY:
+ color_combine = radeon_color_combine[unit][RADEON_BLEND];
+ alpha_combine = radeon_alpha_combine[unit][RADEON_BLEND];
+ break;
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if ( rmesa->hw.tex[unit].cmd[TEX_PP_TXCBLEND] != color_combine ||
+ rmesa->hw.tex[unit].cmd[TEX_PP_TXABLEND] != alpha_combine ) {
+ RADEON_STATECHANGE( rmesa, tex[unit] );
+ rmesa->hw.tex[unit].cmd[TEX_PP_TXCBLEND] = color_combine;
+ rmesa->hw.tex[unit].cmd[TEX_PP_TXABLEND] = alpha_combine;
+ }
+}
+
+
+#define TEXOBJ_TXFILTER_MASK (RADEON_MAX_MIP_LEVEL_MASK | \
+ RADEON_MIN_FILTER_MASK | \
+ RADEON_MAG_FILTER_MASK | \
+ RADEON_MAX_ANISO_MASK | \
+ RADEON_CLAMP_S_MASK | \
+ RADEON_CLAMP_T_MASK)
+
+#define TEXOBJ_TXFORMAT_MASK (RADEON_TXFORMAT_WIDTH_MASK | \
+ RADEON_TXFORMAT_HEIGHT_MASK | \
+ RADEON_TXFORMAT_FORMAT_MASK | \
+ RADEON_TXFORMAT_ALPHA_IN_MAP)
+
+
+
+void radeonUpdateTextureState( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[0];
+
+ if ( texUnit->_ReallyEnabled & (TEXTURE_1D_BIT | TEXTURE_2D_BIT) ) {
+ struct gl_texture_object *tObj = texUnit->_Current;
+ radeonTexObjPtr t = (radeonTexObjPtr) tObj->DriverData;
+
+ /* Upload teximages (not pipelined)
+ */
+ if ( t->dirty_images ) {
+ RADEON_FIREVERTICES( rmesa );
+ radeonSetTexImages( rmesa, tObj );
+ }
+
+ /* Update state if this is a different texture object to last
+ * time.
+ */
+ if ( rmesa->state.texture.unit[0].texobj != t ) {
+ rmesa->state.texture.unit[0].texobj = t;
+ t->dirty_state |= 1<<0;
+ move_to_head( &rmesa->texture.objects[0], t );
+ }
+
+ if (t->dirty_state) {
+ GLuint *cmd = RADEON_DB_STATE( tex[0] );
+
+ cmd[TEX_PP_TXFILTER] &= ~TEXOBJ_TXFILTER_MASK;
+ cmd[TEX_PP_TXFORMAT] &= ~TEXOBJ_TXFORMAT_MASK;
+ cmd[TEX_PP_TXFILTER] |= t->pp_txfilter & TEXOBJ_TXFILTER_MASK;
+ cmd[TEX_PP_TXFORMAT] |= t->pp_txformat & TEXOBJ_TXFORMAT_MASK;
+ cmd[TEX_PP_TXOFFSET] = t->pp_txoffset;
+ cmd[TEX_PP_BORDER_COLOR] = t->pp_border_color;
+
+ RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.tex[0] );
+ t->dirty_state = 0;
+ }
+
+ /* Newly enabled?
+ */
+ if (!(rmesa->hw.ctx.cmd[CTX_PP_CNTL] & RADEON_TEX_0_ENABLE)) {
+ RADEON_STATECHANGE( rmesa, ctx );
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= (RADEON_TEX_0_ENABLE |
+ RADEON_TEX_BLEND_0_ENABLE);
+
+ RADEON_STATECHANGE( rmesa, tcl );
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_ST0;
+ }
+
+ radeonUpdateTextureEnv( ctx, 0 );
+ }
+ else if (rmesa->hw.ctx.cmd[CTX_PP_CNTL] & (RADEON_TEX_0_ENABLE<<0)) {
+ /* Texture unit disabled */
+ rmesa->state.texture.unit[0].texobj = 0;
+ RADEON_STATECHANGE( rmesa, ctx );
+ rmesa->hw.ctx.cmd[CTX_PP_CNTL] &=
+ ~((RADEON_TEX_0_ENABLE | RADEON_TEX_BLEND_0_ENABLE) << 0);
+
+ RADEON_STATECHANGE( rmesa, tcl );
+ rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &= ~(RADEON_TCL_VTX_ST0 |
+ RADEON_TCL_VTX_Q0);
+ }
+}
+
+
+
+/**
+ * \brief Choose texture format.
+ *
+ * \param ctx GL context.
+ * \param internalFormat texture internal format.
+ * \param format pixel format. Not used.
+ * \param type pixel data type. Not used.
+ *
+ * \return pointer to chosen texture format.
+ *
+ * Returns a pointer to one of the Mesa texture formats which is supported by
+ * Radeon and matches the internal format.
+ */
+static const struct gl_texture_format *
+radeonChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
+ GLenum format, GLenum type )
+{
+ switch ( internalFormat ) {
+ case GL_RGBA:
+ case GL_RGBA8:
+ return &_mesa_texformat_rgba8888;
+
+ case GL_RGB:
+ case GL_RGB5:
+ return &_mesa_texformat_rgb565;
+
+ case GL_INTENSITY:
+ case GL_INTENSITY8:
+ return &_mesa_texformat_i8;
+
+ default:
+ _mesa_problem(ctx, "unexpected texture format in radeonChoosTexFormat");
+ return NULL;
+ }
+}
+
+/**
+ * \brief Allocate a Radeon texture object.
+ *
+ * \param texObj texture object.
+ *
+ * \return pointer to the device specific texture object on success, or NULL on failure.
+ *
+ * Allocates and initializes a radeon_tex_obj structure to connect it to the
+ * driver private data pointer in \p texObj.
+ */
+static radeonTexObjPtr radeonAllocTexObj( struct gl_texture_object *texObj )
+{
+ radeonTexObjPtr t;
+
+ t = CALLOC_STRUCT( radeon_tex_obj );
+ if (!t)
+ return NULL;
+
+ t->tObj = texObj;
+ texObj->DriverData = t;
+ make_empty_list( t );
+ t->dirty_images = ~0;
+ return t;
+}
+
+
+/**
+ * \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 Set texture environment parameters.
+ *
+ * \param ctx GL context.
+ * \param target texture environment.
+ * \param pname texture parameter. Accepted value is GL_TEXTURE_ENV_COLOR.
+ * \param param parameter value.
+ *
+ * Updates the current unit's RADEON_TEX_PP_TFACTOR register and informs of the
+ * state change.
+ */
+static void radeonTexEnv( GLcontext *ctx, GLenum target,
+ GLenum pname, const GLfloat *param )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ GLuint unit = ctx->Texture.CurrentUnit;
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+
+ switch ( pname ) {
+ case GL_TEXTURE_ENV_COLOR: {
+ GLubyte c[4];
+ GLuint envColor;
+ UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor );
+ envColor = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
+ if ( rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] != envColor ) {
+ RADEON_STATECHANGE( rmesa, tex[unit] );
+ rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] = envColor;
+ }
+ break;
+ }
+
+ default:
+ return;
+ }
+}
+
+/**
+ * \brief Set texture parameter.
+ *
+ * \param ctx GL context.
+ * \param target target texture.
+ * \param texObj texture object.
+ * \param pname texture parameter.
+ * \param params parameter value.
+ *
+ * Allocates the device specific texture object data if it doesn't exist
+ * already.
+ *
+ * Updates the texture object radeon_tex_obj::pp_txfilter register and marks
+ * the texture state (radeon_tex_obj::dirty_state) as dirty.
+ */
+static void radeonTexParameter( GLcontext *ctx, GLenum target,
+ struct gl_texture_object *texObj,
+ GLenum pname, const GLfloat *params )
+{
+ radeonTexObjPtr t = (radeonTexObjPtr) texObj->DriverData;
+
+ if (!t)
+ t = radeonAllocTexObj( texObj );
+
+ switch ( pname ) {
+ case GL_TEXTURE_MIN_FILTER:
+ t->pp_txfilter &= ~RADEON_MIN_FILTER_MASK;
+ switch ( texObj->MinFilter ) {
+ case GL_NEAREST:
+ t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST;
+ break;
+ case GL_LINEAR:
+ t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR;
+ break;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_NEAREST;
+ break;
+ case GL_NEAREST_MIPMAP_LINEAR:
+ t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_NEAREST;
+ break;
+ case GL_LINEAR_MIPMAP_NEAREST:
+ t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_LINEAR;
+ break;
+ case GL_LINEAR_MIPMAP_LINEAR:
+ t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_LINEAR;
+ break;
+ }
+ break;
+
+ case GL_TEXTURE_MAG_FILTER:
+ t->pp_txfilter &= ~RADEON_MAG_FILTER_MASK;
+ switch ( texObj->MagFilter ) {
+ case GL_NEAREST:
+ t->pp_txfilter |= RADEON_MAG_FILTER_NEAREST;
+ break;
+ case GL_LINEAR:
+ t->pp_txfilter |= RADEON_MAG_FILTER_LINEAR;
+ break;
+ }
+ break;
+
+ case GL_TEXTURE_WRAP_S:
+ t->pp_txfilter &= ~RADEON_CLAMP_S_MASK;
+ switch ( texObj->WrapS ) {
+ case GL_REPEAT:
+ t->pp_txfilter |= RADEON_CLAMP_S_WRAP;
+ break;
+ case GL_CLAMP_TO_EDGE:
+ t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_LAST;
+ break;
+ }
+ break;
+
+ case GL_TEXTURE_WRAP_T:
+ t->pp_txfilter &= ~RADEON_CLAMP_T_MASK;
+ switch ( texObj->WrapT ) {
+ case GL_REPEAT:
+ t->pp_txfilter |= RADEON_CLAMP_T_WRAP;
+ break;
+ case GL_CLAMP_TO_EDGE:
+ t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_LAST;
+ break;
+ }
+ break;
+
+ default:
+ return;
+ }
+
+ /* Mark this texobj as dirty (one bit per tex unit)
+ */
+ t->dirty_state = TEX_ALL;
+}
+
+/**
+ * \brief Bind texture.
+ *
+ * \param ctx GL context.
+ * \param target not used.
+ * \param texObj texture object.
+ *
+ * Allocates the device specific texture data if it doesn't exist already.
+ */
+static void radeonBindTexture( GLcontext *ctx, GLenum target,
+ struct gl_texture_object *texObj )
+{
+ if ( !texObj->DriverData )
+ radeonAllocTexObj( texObj );
+}
+
+/**
+ * \brief Delete texture.
+ *
+ * \param ctx GL context.
+ * \param texObj texture object.
+ *
+ * Fires any outstanding vertices and destroy the device specific texture
+ * object.
+ */
+static void radeonDeleteTexture( GLcontext *ctx,
+ struct gl_texture_object *texObj )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ radeonTexObjPtr t = (radeonTexObjPtr) texObj->DriverData;
+
+ if ( t ) {
+ if ( rmesa )
+ RADEON_FIREVERTICES( rmesa );
+ radeonDestroyTexObj( rmesa, t );
+ }
+}
+
+/**
+ * \brief Initialize context texture object data.
+ *
+ * \param ctx GL context.
+ *
+ * Called by radeonInitTextureFuncs() to setup the context initial texture
+ * objects.
+ */
+static void radeonInitTextureObjects( GLcontext *ctx )
+{
+ radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
+ struct gl_texture_object *texObj;
+ GLuint tmp = ctx->Texture.CurrentUnit;
+
+ ctx->Texture.CurrentUnit = 0;
+
+ texObj = ctx->Texture.Unit[0].Current2D;
+ radeonBindTexture( ctx, GL_TEXTURE_2D, texObj );
+ move_to_tail( &rmesa->texture.swapped,
+ (radeonTexObjPtr)texObj->DriverData );
+
+
+ ctx->Texture.CurrentUnit = tmp;
+}
+
+/**
+ * \brief Setup the GL context driver callbacks.
+ *
+ * \param ctx GL context.
+ *
+ * \sa Called by radeonCreateContext().
+ */
+void radeonInitTextureFuncs( GLcontext *ctx )
+{
+ ctx->Driver.ChooseTextureFormat = radeonChooseTextureFormat;
+ ctx->Driver.TexImage2D = radeonTexImage2D;
+
+ ctx->Driver.BindTexture = radeonBindTexture;
+ ctx->Driver.CreateTexture = NULL; /* FIXME: Is this used??? */
+ ctx->Driver.DeleteTexture = radeonDeleteTexture;
+ ctx->Driver.PrioritizeTexture = NULL;
+ ctx->Driver.ActiveTexture = NULL;
+ ctx->Driver.UpdateTexturePalette = NULL;
+
+ ctx->Driver.TexEnv = radeonTexEnv;
+ ctx->Driver.TexParameter = radeonTexParameter;
+
+ radeonInitTextureObjects( ctx );
+}
+
+/*@}*/