blob: f657abe6711e9d8e4e0294b69b4eb56d65076ff7 [file] [log] [blame]
/*
* GLX Hardware Device Driver for Intel i810
* Copyright (C) 1999 Keith Whitwell
*
* 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 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
* KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS 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/i810/i810tex.c,v 1.9 2002/10/30 12:51:33 alanh Exp $ */
#include "glheader.h"
#include "mtypes.h"
#include "imports.h"
#include "simple_list.h"
#include "enums.h"
#include "texstore.h"
#include "texformat.h"
#include "teximage.h"
#include "texmem.h"
#include "texobj.h"
#include "swrast/swrast.h"
#include "colormac.h"
#include "texobj.h"
#include "mm.h"
#include "i810screen.h"
#include "i810_dri.h"
#include "i810context.h"
#include "i810tex.h"
#include "i810state.h"
#include "i810ioctl.h"
/*
* Compute the 'S2.4' lod bias factor from the floating point OpenGL bias.
*/
static GLuint i810ComputeLodBias(GLfloat bias)
{
int b = (int) (bias * 16.0) + 12;
if (b > 63)
b = 63;
else if (b < -64)
b = -64;
return (GLuint) (b & MLC_LOD_BIAS_MASK);
}
static void i810SetTexWrapping(i810TextureObjectPtr tex,
GLenum swrap, GLenum twrap)
{
tex->Setup[I810_TEXREG_MCS] &= ~(MCS_U_STATE_MASK| MCS_V_STATE_MASK);
switch( swrap ) {
case GL_REPEAT:
tex->Setup[I810_TEXREG_MCS] |= MCS_U_WRAP;
break;
case GL_CLAMP:
case GL_CLAMP_TO_EDGE:
tex->Setup[I810_TEXREG_MCS] |= MCS_U_CLAMP;
break;
case GL_MIRRORED_REPEAT:
tex->Setup[I810_TEXREG_MCS] |= MCS_U_MIRROR;
break;
default:
_mesa_problem(NULL, "bad S wrap mode in %s", __FUNCTION__);
}
switch( twrap ) {
case GL_REPEAT:
tex->Setup[I810_TEXREG_MCS] |= MCS_V_WRAP;
break;
case GL_CLAMP:
case GL_CLAMP_TO_EDGE:
tex->Setup[I810_TEXREG_MCS] |= MCS_V_CLAMP;
break;
case GL_MIRRORED_REPEAT:
tex->Setup[I810_TEXREG_MCS] |= MCS_V_MIRROR;
break;
default:
_mesa_problem(NULL, "bad T wrap mode in %s", __FUNCTION__);
}
}
static void i810SetTexFilter(i810ContextPtr imesa,
i810TextureObjectPtr t,
GLenum minf, GLenum magf,
GLfloat bias)
{
t->Setup[I810_TEXREG_MF] &= ~(MF_MIN_MASK|
MF_MAG_MASK|
MF_MIP_MASK);
t->Setup[I810_TEXREG_MLC] &= ~(MLC_LOD_BIAS_MASK);
switch (minf) {
case GL_NEAREST:
t->Setup[I810_TEXREG_MF] |= MF_MIN_NEAREST | MF_MIP_NONE;
break;
case GL_LINEAR:
t->Setup[I810_TEXREG_MF] |= MF_MIN_LINEAR | MF_MIP_NONE;
break;
case GL_NEAREST_MIPMAP_NEAREST:
t->Setup[I810_TEXREG_MF] |= MF_MIN_NEAREST | MF_MIP_NEAREST;
if (magf == GL_LINEAR) {
/*bias -= 0.5;*/ /* this doesn't work too good */
}
break;
case GL_LINEAR_MIPMAP_NEAREST:
t->Setup[I810_TEXREG_MF] |= MF_MIN_LINEAR | MF_MIP_NEAREST;
break;
case GL_NEAREST_MIPMAP_LINEAR:
if (IS_I815(imesa))
t->Setup[I810_TEXREG_MF] |= MF_MIN_NEAREST | MF_MIP_LINEAR;
else
t->Setup[I810_TEXREG_MF] |= MF_MIN_NEAREST | MF_MIP_DITHER;
/*
if (magf == GL_LINEAR) {
bias -= 0.5;
}
*/
bias -= 0.5; /* always biasing here looks better */
break;
case GL_LINEAR_MIPMAP_LINEAR:
if (IS_I815(imesa))
t->Setup[I810_TEXREG_MF] |= MF_MIN_LINEAR | MF_MIP_LINEAR;
else
t->Setup[I810_TEXREG_MF] |= MF_MIN_LINEAR | MF_MIP_DITHER;
break;
default:
return;
}
switch (magf) {
case GL_NEAREST:
t->Setup[I810_TEXREG_MF] |= MF_MAG_NEAREST;
break;
case GL_LINEAR:
t->Setup[I810_TEXREG_MF] |= MF_MAG_LINEAR;
break;
default:
return;
}
t->Setup[I810_TEXREG_MLC] |= i810ComputeLodBias(bias);
}
static void
i810SetTexBorderColor( i810TextureObjectPtr t, GLubyte color[4] )
{
/* Need a fallback.
*/
}
static i810TextureObjectPtr
i810AllocTexObj( GLcontext *ctx, struct gl_texture_object *texObj )
{
i810TextureObjectPtr t;
i810ContextPtr imesa = I810_CONTEXT(ctx);
t = CALLOC_STRUCT( i810_texture_object_t );
texObj->DriverData = t;
if ( t != NULL ) {
GLfloat bias = ctx->Texture.Unit[ctx->Texture.CurrentUnit].LodBias;
/* Initialize non-image-dependent parts of the state:
*/
t->base.tObj = texObj;
t->Setup[I810_TEXREG_MI0] = GFX_OP_MAP_INFO;
t->Setup[I810_TEXREG_MI1] = MI1_MAP_0;
t->Setup[I810_TEXREG_MI2] = MI2_DIMENSIONS_ARE_LOG2;
t->Setup[I810_TEXREG_MLC] = (GFX_OP_MAP_LOD_CTL |
MLC_MAP_0 |
/*MLC_DITHER_WEIGHT_FULL |*/
MLC_DITHER_WEIGHT_12 |
MLC_UPDATE_LOD_BIAS |
0x0);
t->Setup[I810_TEXREG_MCS] = (GFX_OP_MAP_COORD_SETS |
MCS_COORD_0 |
MCS_UPDATE_NORMALIZED |
MCS_NORMALIZED_COORDS |
MCS_UPDATE_V_STATE |
MCS_V_WRAP |
MCS_UPDATE_U_STATE |
MCS_U_WRAP);
t->Setup[I810_TEXREG_MF] = (GFX_OP_MAP_FILTER |
MF_MAP_0 |
MF_UPDATE_ANISOTROPIC |
MF_UPDATE_MIP_FILTER |
MF_UPDATE_MAG_FILTER |
MF_UPDATE_MIN_FILTER);
make_empty_list( & t->base );
i810SetTexWrapping( t, texObj->WrapS, texObj->WrapT );
/*i830SetTexMaxAnisotropy( t, texObj->MaxAnisotropy );*/
i810SetTexFilter( imesa, t, texObj->MinFilter, texObj->MagFilter, bias );
i810SetTexBorderColor( t, texObj->_BorderChan );
}
return t;
}
static void i810TexParameter( GLcontext *ctx, GLenum target,
struct gl_texture_object *tObj,
GLenum pname, const GLfloat *params )
{
i810ContextPtr imesa = I810_CONTEXT(ctx);
i810TextureObjectPtr t = (i810TextureObjectPtr) tObj->DriverData;
if (!t)
return;
if ( target != GL_TEXTURE_2D )
return;
/* Can't do the update now as we don't know whether to flush
* vertices or not. Setting imesa->new_state means that
* i810UpdateTextureState() will be called before any triangles are
* rendered. If a statechange has occurred, it will be detected at
* that point, and buffered vertices flushed.
*/
switch (pname) {
case GL_TEXTURE_MIN_FILTER:
case GL_TEXTURE_MAG_FILTER:
{
GLfloat bias = ctx->Texture.Unit[ctx->Texture.CurrentUnit].LodBias;
i810SetTexFilter( imesa, t, tObj->MinFilter, tObj->MagFilter, bias );
}
break;
case GL_TEXTURE_WRAP_S:
case GL_TEXTURE_WRAP_T:
i810SetTexWrapping( t, tObj->WrapS, tObj->WrapT );
break;
case GL_TEXTURE_BORDER_COLOR:
i810SetTexBorderColor( t, tObj->_BorderChan );
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.
*/
I810_FIREVERTICES( I810_CONTEXT(ctx) );
driSwapOutTextureObject( (driTextureObject *) t );
break;
default:
return;
}
if (t == imesa->CurrentTexObj[0]) {
I810_STATECHANGE( imesa, I810_UPLOAD_TEX0 );
}
if (t == imesa->CurrentTexObj[1]) {
I810_STATECHANGE( imesa, I810_UPLOAD_TEX1 );
}
}
/**
* Setup hardware bits for new texture environment settings.
*
* \todo
* Determine whether or not \c param can be used instead of
* \c texUnit->EnvColor in the \c GL_TEXTURE_ENV_COLOR case.
*/
static void i810TexEnv( GLcontext *ctx, GLenum target,
GLenum pname, const GLfloat *param )
{
i810ContextPtr imesa = I810_CONTEXT( ctx );
const GLuint unit = ctx->Texture.CurrentUnit;
const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
/* Only one env color. Need a fallback if env colors are different
* and texture setup references env color in both units.
*/
switch (pname) {
case GL_TEXTURE_ENV_COLOR: {
GLubyte c[4];
GLuint envColor;
UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor );
envColor = PACK_COLOR_8888( c[3], c[0], c[1], c[2] );
if (imesa->Setup[I810_CTXREG_CF1] != envColor) {
I810_STATECHANGE(imesa, I810_UPLOAD_CTX);
imesa->Setup[I810_CTXREG_CF1] = envColor;
}
break;
}
case GL_TEXTURE_ENV_MODE:
imesa->TexEnvImageFmt[unit] = 0; /* force recalc of env state */
break;
case GL_TEXTURE_LOD_BIAS: {
if ( texUnit->_Current != NULL ) {
const struct gl_texture_object *tObj = texUnit->_Current;
i810TextureObjectPtr t = (i810TextureObjectPtr) tObj->DriverData;
t->Setup[I810_TEXREG_MLC] &= ~(MLC_LOD_BIAS_MASK);
t->Setup[I810_TEXREG_MLC] |= i810ComputeLodBias(*param);
}
break;
}
default:
break;
}
}
#if 0
static void i810TexImage1D( GLcontext *ctx, GLenum target, GLint level,
GLint internalFormat,
GLint width, GLint border,
GLenum format, GLenum type,
const GLvoid *pixels,
const struct gl_pixelstore_attrib *pack,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage )
{
i810TextureObjectPtr t = (i810TextureObjectPtr) texObj->DriverData;
if (t) {
i810SwapOutTexObj( imesa, t );
}
}
static void i810TexSubImage1D( GLcontext *ctx,
GLenum target,
GLint level,
GLint xoffset,
GLsizei width,
GLenum format, GLenum type,
const GLvoid *pixels,
const struct gl_pixelstore_attrib *pack,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage )
{
}
#endif
static void i810TexImage2D( 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 )
{
driTextureObject *t = (driTextureObject *) texObj->DriverData;
if (t) {
I810_FIREVERTICES( I810_CONTEXT(ctx) );
driSwapOutTextureObject( t );
}
else {
t = (driTextureObject *) i810AllocTexObj( ctx, texObj );
if (!t) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
return;
}
}
_mesa_store_teximage2d( ctx, target, level, internalFormat,
width, height, border, format, type,
pixels, packing, texObj, texImage );
}
static void i810TexSubImage2D( 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 )
{
driTextureObject *t = (driTextureObject *)texObj->DriverData;
if (t) {
I810_FIREVERTICES( I810_CONTEXT(ctx) );
driSwapOutTextureObject( t );
}
_mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
height, format, type, pixels, packing, texObj,
texImage);
}
static void i810BindTexture( GLcontext *ctx, GLenum target,
struct gl_texture_object *tObj )
{
assert( (target != GL_TEXTURE_2D) || (tObj->DriverData != NULL) );
}
static void i810DeleteTexture( GLcontext *ctx, struct gl_texture_object *tObj )
{
driTextureObject * t = (driTextureObject *) tObj->DriverData;
if (t) {
i810ContextPtr imesa = I810_CONTEXT( ctx );
if (imesa)
I810_FIREVERTICES( imesa );
driDestroyTextureObject( t );
}
/* Free mipmap images and the texture object itself */
_mesa_delete_texture_object(ctx, tObj);
}
/**
* Choose a Mesa texture format to match the requested format.
*
* The i810 only supports 5 texture modes that are useful to Mesa. That
* makes this routine pretty simple.
*/
static const struct gl_texture_format *
i810ChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
GLenum format, GLenum type )
{
switch ( internalFormat ) {
case 4:
case GL_RGBA:
case GL_RGBA2:
case GL_RGBA4:
case GL_RGB5_A1:
case GL_RGBA8:
case GL_RGB10_A2:
case GL_RGBA12:
case GL_RGBA16:
case GL_COMPRESSED_RGBA:
if ( ((format == GL_BGRA) && (type == GL_UNSIGNED_SHORT_1_5_5_5_REV))
|| ((format == GL_RGBA) && (type == GL_UNSIGNED_SHORT_5_5_5_1))
|| (internalFormat == GL_RGB5_A1) ) {
return &_mesa_texformat_argb1555;
}
return &_mesa_texformat_argb4444;
case 3:
case GL_RGB:
case GL_COMPRESSED_RGB:
case GL_R3_G3_B2:
case GL_RGB4:
case GL_RGB5:
case GL_RGB8:
case GL_RGB10:
case GL_RGB12:
case GL_RGB16:
return &_mesa_texformat_rgb565;
case GL_ALPHA:
case GL_ALPHA4:
case GL_ALPHA8:
case GL_ALPHA12:
case GL_ALPHA16:
case GL_COMPRESSED_ALPHA:
case 1:
case GL_LUMINANCE:
case GL_LUMINANCE4:
case GL_LUMINANCE8:
case GL_LUMINANCE12:
case GL_LUMINANCE16:
case GL_COMPRESSED_LUMINANCE:
case 2:
case GL_LUMINANCE_ALPHA:
case GL_LUMINANCE4_ALPHA4:
case GL_LUMINANCE6_ALPHA2:
case GL_LUMINANCE8_ALPHA8:
case GL_LUMINANCE12_ALPHA4:
case GL_LUMINANCE12_ALPHA12:
case GL_LUMINANCE16_ALPHA16:
case GL_COMPRESSED_LUMINANCE_ALPHA:
case GL_INTENSITY:
case GL_INTENSITY4:
case GL_INTENSITY8:
case GL_INTENSITY12:
case GL_INTENSITY16:
case GL_COMPRESSED_INTENSITY:
return &_mesa_texformat_al88;
case GL_YCBCR_MESA:
if (type == GL_UNSIGNED_SHORT_8_8_MESA ||
type == GL_UNSIGNED_BYTE)
return &_mesa_texformat_ycbcr;
else
return &_mesa_texformat_ycbcr_rev;
default:
fprintf(stderr, "unexpected texture format in %s\n", __FUNCTION__);
return NULL;
}
return NULL; /* never get here */
}
/**
* 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.
* Note: we could use containment here to 'derive' the driver-specific
* texture object from the core mesa gl_texture_object. Not done at this time.
*/
static struct gl_texture_object *
i810NewTextureObject( GLcontext *ctx, GLuint name, GLenum target )
{
struct gl_texture_object *obj;
obj = _mesa_new_texture_object(ctx, name, target);
i810AllocTexObj( ctx, obj );
return obj;
}
void i810InitTextureFuncs( struct dd_function_table *functions )
{
functions->ChooseTextureFormat = i810ChooseTextureFormat;
functions->TexImage2D = i810TexImage2D;
functions->TexSubImage2D = i810TexSubImage2D;
functions->BindTexture = i810BindTexture;
functions->NewTextureObject = i810NewTextureObject;
functions->DeleteTexture = i810DeleteTexture;
functions->TexParameter = i810TexParameter;
functions->TexEnv = i810TexEnv;
functions->IsTextureResident = driIsTextureResident;
}