diff options
author | Alex Deucher <[email protected]> | 2009-07-06 00:00:10 -0400 |
---|---|---|
committer | Alex Deucher <[email protected]> | 2009-07-06 10:25:48 -0400 |
commit | 1bad691a177240e8281592fa66c9e6ab0869f618 (patch) | |
tree | 65a61f156a316678325a934d068da5b76f34693c /src/mesa/drivers/dri/r600/r600_tex.c | |
parent | c6b0b46d6d087de59a36f1340cea54a11df78e37 (diff) |
R6xx/r7xx: first pass at texture support
texture bo setup isn't quite working yet
Diffstat (limited to 'src/mesa/drivers/dri/r600/r600_tex.c')
-rw-r--r-- | src/mesa/drivers/dri/r600/r600_tex.c | 438 |
1 files changed, 438 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/r600/r600_tex.c b/src/mesa/drivers/dri/r600/r600_tex.c new file mode 100644 index 00000000000..5845c05810b --- /dev/null +++ b/src/mesa/drivers/dri/r600/r600_tex.c @@ -0,0 +1,438 @@ +/* +Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. + +The Weather Channel (TM) 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 the rights to use, copy, modify, merge, publish, +distribute, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS 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. +*/ + +/** + * \file + * + * \author Keith Whitwell <[email protected]> + */ + +#include "main/glheader.h" +#include "main/imports.h" +#include "main/colormac.h" +#include "main/context.h" +#include "main/enums.h" +#include "main/image.h" +#include "main/mipmap.h" +#include "main/simple_list.h" +#include "main/texformat.h" +#include "main/texstore.h" +#include "main/teximage.h" +#include "main/texobj.h" + +#include "texmem.h" + +#include "r600_context.h" +#include "r700_state.h" +#include "radeon_mipmap_tree.h" +#include "r600_tex.h" + +#include "xmlpool.h" + + +static unsigned int translate_wrap_mode(GLenum wrapmode) +{ + switch(wrapmode) { + case GL_REPEAT: return SQ_TEX_WRAP; + case GL_CLAMP: return SQ_TEX_CLAMP_HALF_BORDER; + case GL_CLAMP_TO_EDGE: return SQ_TEX_CLAMP_LAST_TEXEL; + case GL_CLAMP_TO_BORDER: return SQ_TEX_CLAMP_BORDER; + case GL_MIRRORED_REPEAT: return SQ_TEX_MIRROR_ONCE_HALF_BORDER; + case GL_MIRROR_CLAMP_EXT: return SQ_TEX_MIRROR; + case GL_MIRROR_CLAMP_TO_EDGE_EXT: return SQ_TEX_MIRROR_ONCE_BORDER; + case GL_MIRROR_CLAMP_TO_BORDER_EXT: return SQ_TEX_MIRROR_ONCE_LAST_TEXEL; + default: + _mesa_problem(NULL, "bad wrap mode in %s", __FUNCTION__); + return 0; + } +} + + +/** + * Update the cached hardware registers based on the current texture wrap modes. + * + * \param t Texture object whose wrap modes are to be set + */ +static void r600UpdateTexWrap(radeonTexObjPtr t) +{ + struct gl_texture_object *tObj = &t->base; + + SETfield(t->SQ_TEX_SAMPLER0, translate_wrap_mode(tObj->WrapS), + SQ_TEX_SAMPLER_WORD0_0__CLAMP_X_shift, SQ_TEX_SAMPLER_WORD0_0__CLAMP_X_mask); + + if (tObj->Target != GL_TEXTURE_1D) { + SETfield(t->SQ_TEX_SAMPLER0, translate_wrap_mode(tObj->WrapT), + CLAMP_Y_shift, CLAMP_Y_mask); + + if (tObj->Target == GL_TEXTURE_3D) + SETfield(t->SQ_TEX_SAMPLER0, translate_wrap_mode(tObj->WrapR), + CLAMP_Z_shift, CLAMP_Z_mask); + } +} + +static void r600SetTexDefaultState(radeonTexObjPtr t) +{ + /* Init text object to default states. */ + t->SQ_TEX_RESOURCE0 = 0; + SETfield(t->SQ_TEX_RESOURCE0, SQ_TEX_DIM_2D, DIM_shift, DIM_mask); + SETfield(t->SQ_TEX_RESOURCE0, ARRAY_LINEAR_GENERAL, + SQ_TEX_RESOURCE_WORD0_0__TILE_MODE_shift, SQ_TEX_RESOURCE_WORD0_0__TILE_MODE_mask); + CLEARbit(t->SQ_TEX_RESOURCE0, TILE_TYPE_bit); + + t->SQ_TEX_RESOURCE1 = 0; + SETfield(t->SQ_TEX_RESOURCE1, FMT_8_8_8_8, + SQ_TEX_RESOURCE_WORD1_0__DATA_FORMAT_shift, SQ_TEX_RESOURCE_WORD1_0__DATA_FORMAT_mask); + + t->SQ_TEX_RESOURCE2 = 0; + t->SQ_TEX_RESOURCE3 = 0; + + t->SQ_TEX_RESOURCE4 = 0; + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_UNSIGNED, + FORMAT_COMP_X_shift, FORMAT_COMP_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_UNSIGNED, + FORMAT_COMP_Y_shift, FORMAT_COMP_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_UNSIGNED, + FORMAT_COMP_Z_shift, FORMAT_COMP_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_UNSIGNED, + FORMAT_COMP_W_shift, FORMAT_COMP_W_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_NUM_FORMAT_NORM, + SQ_TEX_RESOURCE_WORD4_0__NUM_FORMAT_ALL_shift, SQ_TEX_RESOURCE_WORD4_0__NUM_FORMAT_ALL_mask); + CLEARbit(t->SQ_TEX_RESOURCE4, SQ_TEX_RESOURCE_WORD4_0__SRF_MODE_ALL_bit); + CLEARbit(t->SQ_TEX_RESOURCE4, SQ_TEX_RESOURCE_WORD4_0__FORCE_DEGAMMA_bit); + SETfield(t->SQ_TEX_RESOURCE4, SQ_ENDIAN_NONE, + SQ_TEX_RESOURCE_WORD4_0__ENDIAN_SWAP_shift, SQ_TEX_RESOURCE_WORD4_0__ENDIAN_SWAP_mask); + SETfield(t->SQ_TEX_RESOURCE4, 1, REQUEST_SIZE_shift, REQUEST_SIZE_mask); + t->SQ_TEX_RESOURCE4 |= SQ_SEL_X << SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift + |SQ_SEL_Y << SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift + |SQ_SEL_Z << SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift + |SQ_SEL_W << SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift; + SETfield(t->SQ_TEX_RESOURCE4, 0, BASE_LEVEL_shift, BASE_LEVEL_mask); /* mip-maps */ + + t->SQ_TEX_RESOURCE5 = 0; + t->SQ_TEX_RESOURCE6 = 0; + + SETfield(t->SQ_TEX_RESOURCE6, SQ_TEX_VTX_VALID_TEXTURE, + SQ_TEX_RESOURCE_WORD6_0__TYPE_shift, SQ_TEX_RESOURCE_WORD6_0__TYPE_mask); + + /* Initialize sampler registers */ + t->SQ_TEX_SAMPLER0 = 0; + t->SQ_TEX_SAMPLER0 |= + SQ_TEX_WRAP << SQ_TEX_SAMPLER_WORD0_0__CLAMP_X_shift + |SQ_TEX_WRAP << CLAMP_Y_shift + |SQ_TEX_WRAP << CLAMP_Z_shift + |SQ_TEX_XY_FILTER_POINT << XY_MAG_FILTER_shift + |SQ_TEX_XY_FILTER_POINT << XY_MIN_FILTER_shift + |SQ_TEX_Z_FILTER_NONE << Z_FILTER_shift + |SQ_TEX_Z_FILTER_NONE << MIP_FILTER_shift + |SQ_TEX_BORDER_COLOR_TRANS_BLACK << BORDER_COLOR_TYPE_shift; + + t->SQ_TEX_SAMPLER1 = 0x7FF << MAX_LOD_shift; + + t->SQ_TEX_SAMPLER2 = 0; + SETbit(t->SQ_TEX_SAMPLER2, SQ_TEX_SAMPLER_WORD2_0__TYPE_bit); +} + + +static GLuint aniso_filter(GLfloat anisotropy) +{ +#if 0 + if (anisotropy >= 16.0) { + return R300_TX_MAX_ANISO_16_TO_1; + } else if (anisotropy >= 8.0) { + return R300_TX_MAX_ANISO_8_TO_1; + } else if (anisotropy >= 4.0) { + return R300_TX_MAX_ANISO_4_TO_1; + } else if (anisotropy >= 2.0) { + return R300_TX_MAX_ANISO_2_TO_1; + } else { + return R300_TX_MAX_ANISO_1_TO_1; + } +#endif + return 0; +} + +/** + * Set the texture magnification and minification modes. + * + * \param t Texture whose filter modes are to be set + * \param minf Texture minification mode + * \param magf Texture magnification mode + * \param anisotropy Maximum anisotropy level + */ +static void r600SetTexFilter(radeonTexObjPtr t, GLenum minf, GLenum magf, GLfloat anisotropy) +{ + /* Force revalidation to account for switches from/to mipmapping. */ + t->validated = GL_FALSE; + + /* Note that EXT_texture_filter_anisotropic is extremely vague about + * how anisotropic filtering interacts with the "normal" filter modes. + * When anisotropic filtering is enabled, we override min and mag + * filter settings completely. This includes driconf's settings. + */ + if (anisotropy >= 2.0 && (minf != GL_NEAREST) && (magf != GL_NEAREST)) { + /*t->pp_txfilter |= R300_TX_MAG_FILTER_ANISO + | R300_TX_MIN_FILTER_ANISO + | R300_TX_MIN_FILTER_MIP_LINEAR + | aniso_filter(anisotropy);*/ + if (RADEON_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, "Using maximum anisotropy of %f\n", anisotropy); + return; + } + + switch (minf) { + case GL_NEAREST: + SETfield(t->SQ_TEX_SAMPLER0, TEX_XYFilter_Point, + XY_MIN_FILTER_shift, XY_MIN_FILTER_mask); + SETfield(t->SQ_TEX_SAMPLER0, TEX_MipFilter_None, + MIP_FILTER_shift, MIP_FILTER_mask); + break; + case GL_LINEAR: + SETfield(t->SQ_TEX_SAMPLER0, TEX_XYFilter_Linear, + XY_MIN_FILTER_shift, XY_MIN_FILTER_mask); + SETfield(t->SQ_TEX_SAMPLER0, TEX_MipFilter_None, + MIP_FILTER_shift, MIP_FILTER_mask); + break; + case GL_NEAREST_MIPMAP_NEAREST: + SETfield(t->SQ_TEX_SAMPLER0, TEX_XYFilter_Point, + XY_MIN_FILTER_shift, XY_MIN_FILTER_mask); + SETfield(t->SQ_TEX_SAMPLER0, TEX_MipFilter_Point, + MIP_FILTER_shift, MIP_FILTER_mask); + break; + case GL_NEAREST_MIPMAP_LINEAR: + SETfield(t->SQ_TEX_SAMPLER0, TEX_XYFilter_Point, + XY_MIN_FILTER_shift, XY_MIN_FILTER_mask); + SETfield(t->SQ_TEX_SAMPLER0, TEX_MipFilter_Linear, + MIP_FILTER_shift, MIP_FILTER_mask); + break; + case GL_LINEAR_MIPMAP_NEAREST: + SETfield(t->SQ_TEX_SAMPLER0, TEX_XYFilter_Linear, + XY_MIN_FILTER_shift, XY_MIN_FILTER_mask); + SETfield(t->SQ_TEX_SAMPLER0, TEX_MipFilter_Point, + MIP_FILTER_shift, MIP_FILTER_mask); + break; + case GL_LINEAR_MIPMAP_LINEAR: + SETfield(t->SQ_TEX_SAMPLER0, TEX_XYFilter_Linear, + XY_MIN_FILTER_shift, XY_MIN_FILTER_mask); + SETfield(t->SQ_TEX_SAMPLER0, TEX_MipFilter_Linear, + MIP_FILTER_shift, MIP_FILTER_mask); + break; + } + + /* Note we don't have 3D mipmaps so only use the mag filter setting + * to set the 3D texture filter mode. + */ + switch (magf) { + case GL_NEAREST: + SETfield(t->SQ_TEX_SAMPLER0, TEX_XYFilter_Point, + XY_MAG_FILTER_shift, XY_MAG_FILTER_mask); + break; + case GL_LINEAR: + SETfield(t->SQ_TEX_SAMPLER0, TEX_XYFilter_Linear, + XY_MAG_FILTER_shift, XY_MAG_FILTER_mask); + break; + } +} + +static void r600SetTexBorderColor(radeonTexObjPtr t, const GLfloat color[4]) +{ +#if 0 + GLubyte c[4]; + CLAMPED_FLOAT_TO_UBYTE(c[0], color[0]); + CLAMPED_FLOAT_TO_UBYTE(c[1], color[1]); + CLAMPED_FLOAT_TO_UBYTE(c[2], color[2]); + CLAMPED_FLOAT_TO_UBYTE(c[3], color[3]); + t->pp_border_color = PACK_COLOR_8888(c[3], c[0], c[1], c[2]); +#endif +} + +/** + * Changes variables and flags for a state update, which will happen at the + * next UpdateTextureState + */ + +static void r600TexParameter(GLcontext * ctx, GLenum target, + struct gl_texture_object *texObj, + GLenum pname, const GLfloat * params) +{ + radeonTexObj* t = radeon_tex_obj(texObj); + + if (RADEON_DEBUG & (DEBUG_STATE | DEBUG_TEXTURE)) { + fprintf(stderr, "%s( %s )\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(pname)); + } + + switch (pname) { + case GL_TEXTURE_MIN_FILTER: + case GL_TEXTURE_MAG_FILTER: + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + r600SetTexFilter(t, texObj->MinFilter, texObj->MagFilter, texObj->MaxAnisotropy); + break; + + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + case GL_TEXTURE_WRAP_R: + r600UpdateTexWrap(t); + break; + + case GL_TEXTURE_BORDER_COLOR: + r600SetTexBorderColor(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. Since there's no LOD clamping, + * we just have to rely on loading the right subset of mipmap levels + * to simulate a clamped LOD. + */ + if (t->mt) { + radeon_miptree_unreference(t->mt); + t->mt = 0; + t->validated = GL_FALSE; + } + break; + + case GL_DEPTH_TEXTURE_MODE: + if (!texObj->Image[0][texObj->BaseLevel]) + return; + if (texObj->Image[0][texObj->BaseLevel]->TexFormat->BaseFormat + == GL_DEPTH_COMPONENT) { + r600SetDepthTexMode(texObj); + break; + } else { + /* If the texture isn't a depth texture, changing this + * state won't cause any changes to the hardware. + * Don't force a flush of texture state. + */ + return; + } + + default: + return; + } +} + +static void r600DeleteTexture(GLcontext * ctx, struct gl_texture_object *texObj) +{ + context_t* rmesa = R700_CONTEXT(ctx); + radeonTexObj* t = radeon_tex_obj(texObj); + + if (RADEON_DEBUG & (DEBUG_STATE | DEBUG_TEXTURE)) { + fprintf(stderr, "%s( %p (target = %s) )\n", __FUNCTION__, + (void *)texObj, + _mesa_lookup_enum_by_nr(texObj->Target)); + } + + if (rmesa) { + // fixme + int i; + //radeon_firevertices(&rmesa->radeon); + + for(i = 0; i < R700_MAX_TEXTURE_UNITS; ++i) + if (rmesa->hw.textures[i] == t) + rmesa->hw.textures[i] = 0; + } + + if (t->bo) { + radeon_bo_unref(t->bo); + t->bo = NULL; + } + + if (t->mt) { + radeon_miptree_unreference(t->mt); + t->mt = 0; + } + _mesa_delete_texture_object(ctx, texObj); +} + +/** + * Allocate a new texture object. + * Called via ctx->Driver.NewTextureObject. + * Note: this function will be called during context creation to + * allocate the default texture objects. + * Fixup MaxAnisotropy according to user preference. + */ +static struct gl_texture_object *r600NewTextureObject(GLcontext * ctx, + GLuint name, + GLenum target) +{ + context_t* rmesa = R700_CONTEXT(ctx); + radeonTexObj* t = CALLOC_STRUCT(radeon_tex_obj); + + + if (RADEON_DEBUG & (DEBUG_STATE | DEBUG_TEXTURE)) { + fprintf(stderr, "%s( %p (target = %s) )\n", __FUNCTION__, + t, _mesa_lookup_enum_by_nr(target)); + } + + _mesa_initialize_texture_object(&t->base, name, target); + t->base.MaxAnisotropy = rmesa->radeon.initialMaxAnisotropy; + + /* Initialize hardware state */ + r600SetTexDefaultState(t); + r600UpdateTexWrap(t); + r600SetTexFilter(t, t->base.MinFilter, t->base.MagFilter, t->base.MaxAnisotropy); + r600SetTexBorderColor(t, t->base.BorderColor); + + return &t->base; +} + +void r600InitTextureFuncs(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 = radeonNewTextureImage; + functions->FreeTexImageData = radeonFreeTexImageData; + functions->MapTexture = radeonMapTexture; + functions->UnmapTexture = radeonUnmapTexture; + + functions->ChooseTextureFormat = radeonChooseTextureFormat_mesa; + functions->TexImage1D = radeonTexImage1D; + functions->TexImage2D = radeonTexImage2D; + functions->TexImage3D = radeonTexImage3D; + functions->TexSubImage1D = radeonTexSubImage1D; + functions->TexSubImage2D = radeonTexSubImage2D; + functions->TexSubImage3D = radeonTexSubImage3D; + functions->GetTexImage = radeonGetTexImage; + functions->GetCompressedTexImage = radeonGetCompressedTexImage; + functions->NewTextureObject = r600NewTextureObject; + functions->DeleteTexture = r600DeleteTexture; + functions->IsTextureResident = driIsTextureResident; + + functions->TexParameter = r600TexParameter; + + functions->CompressedTexImage2D = radeonCompressedTexImage2D; + functions->CompressedTexSubImage2D = radeonCompressedTexSubImage2D; + + functions->GenerateMipmap = radeonGenerateMipmap; + + driInitTextureFormats(); +} |