/* -*- mode: c; c-basic-offset: 3 -*- */ /* * Copyright 2000 Gareth Hughes * 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 * 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 * GARETH HUGHES 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: * Gareth Hughes * Leif Delgass * José Fonseca */ #include "mach64_context.h" #include "mach64_ioctl.h" #include "mach64_tex.h" #include "main/simple_list.h" #include "main/enums.h" #include "main/texstore.h" #include "main/teximage.h" #include "main/texobj.h" #include "main/imports.h" static void mach64SetTexWrap( mach64TexObjPtr t, GLenum swrap, GLenum twrap ) { switch ( swrap ) { case GL_CLAMP: case GL_CLAMP_TO_EDGE: case GL_CLAMP_TO_BORDER: t->ClampS = GL_TRUE; break; case GL_REPEAT: t->ClampS = GL_FALSE; break; } switch ( twrap ) { case GL_CLAMP: case GL_CLAMP_TO_EDGE: case GL_CLAMP_TO_BORDER: t->ClampT = GL_TRUE; break; case GL_REPEAT: t->ClampT = GL_FALSE; break; } } static void mach64SetTexFilter( mach64TexObjPtr t, GLenum minf, GLenum magf ) { switch ( minf ) { case GL_NEAREST: case GL_NEAREST_MIPMAP_NEAREST: case GL_NEAREST_MIPMAP_LINEAR: t->BilinearMin = GL_FALSE; break; case GL_LINEAR: case GL_LINEAR_MIPMAP_NEAREST: case GL_LINEAR_MIPMAP_LINEAR: t->BilinearMin = GL_TRUE; break; } switch ( magf ) { case GL_NEAREST: t->BilinearMag = GL_FALSE; break; case GL_LINEAR: t->BilinearMag = GL_TRUE; break; } } static void mach64SetTexBorderColor( mach64TexObjPtr t, const GLfloat c[4] ) { #if 0 GLuint border = mach64PackColor( 4, c[0], c[1], c[2], c[3] ); #endif } static mach64TexObjPtr mach64AllocTexObj( struct gl_texture_object *texObj ) { mach64TexObjPtr t; if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) fprintf( stderr, "%s( %p )\n", __FUNCTION__, texObj ); t = (mach64TexObjPtr) CALLOC_STRUCT( mach64_texture_object ); texObj->DriverData = t; if ( !t ) return NULL; /* Initialize non-image-dependent parts of the state: */ t->base.tObj = texObj; t->base.dirty_images[0] = (1 << 0); t->bufAddr = 0; make_empty_list( (driTextureObject *) t ); mach64SetTexWrap( t, texObj->WrapS, texObj->WrapT ); mach64SetTexFilter( t, texObj->MinFilter, texObj->MagFilter ); mach64SetTexBorderColor( t, texObj->BorderColor.f ); return t; } /* Called by the _mesa_store_teximage[123]d() functions. */ static gl_format mach64ChooseTextureFormat( struct gl_context *ctx, GLint internalFormat, GLenum format, GLenum type ) { mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); (void) format; (void) type; switch ( internalFormat ) { case GL_ALPHA: case GL_ALPHA4: case GL_ALPHA8: case GL_ALPHA12: case GL_ALPHA16: case GL_COMPRESSED_ALPHA: 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 4: case GL_RGBA: case GL_RGBA2: case GL_COMPRESSED_RGBA: if (mmesa->mach64Screen->cpp == 4) return MESA_FORMAT_ARGB8888; else return MESA_FORMAT_ARGB4444; case GL_RGB5_A1: if (mmesa->mach64Screen->cpp == 4) return MESA_FORMAT_ARGB8888; else return MESA_FORMAT_ARGB1555; case GL_RGBA8: case GL_RGB10_A2: case GL_RGBA12: case GL_RGBA16: case GL_RGBA4: if (mmesa->mach64Screen->cpp == 4) return MESA_FORMAT_ARGB8888; else return MESA_FORMAT_ARGB4444; case 3: case GL_RGB: case GL_R3_G3_B2: case GL_RGB4: case GL_RGB5: case GL_RGB8: case GL_RGB10: case GL_RGB12: case GL_RGB16: case GL_COMPRESSED_RGB: if (mmesa->mach64Screen->cpp == 4) return MESA_FORMAT_ARGB8888; else return MESA_FORMAT_RGB565; case 1: case GL_LUMINANCE: case GL_LUMINANCE4: case GL_LUMINANCE8: case GL_LUMINANCE12: case GL_LUMINANCE16: case GL_COMPRESSED_LUMINANCE: if (mmesa->mach64Screen->cpp == 4) return MESA_FORMAT_ARGB8888; /* inefficient but accurate */ else return MESA_FORMAT_ARGB1555; case GL_INTENSITY4: case GL_INTENSITY: case GL_INTENSITY8: case GL_INTENSITY12: case GL_INTENSITY16: case GL_COMPRESSED_INTENSITY: if (mmesa->mach64Screen->cpp == 4) return MESA_FORMAT_ARGB8888; /* inefficient but accurate */ else return MESA_FORMAT_ARGB4444; case GL_COLOR_INDEX: case GL_COLOR_INDEX1_EXT: case GL_COLOR_INDEX2_EXT: case GL_COLOR_INDEX4_EXT: case GL_COLOR_INDEX8_EXT: case GL_COLOR_INDEX12_EXT: case GL_COLOR_INDEX16_EXT: return MESA_FORMAT_CI8; case GL_YCBCR_MESA: if (type == GL_UNSIGNED_SHORT_8_8_APPLE || type == GL_UNSIGNED_BYTE) return MESA_FORMAT_YCBCR; else return MESA_FORMAT_YCBCR_REV; default: _mesa_problem( ctx, "unexpected format in %s", __FUNCTION__ ); return MESA_FORMAT_NONE; } } static void mach64TexImage1D( struct gl_context *ctx, GLenum target, GLint level, GLint internalFormat, GLint width, 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 ) { mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); driTextureObject * t = (driTextureObject *) texObj->DriverData; if ( t ) { driSwapOutTextureObject( t ); } else { t = (driTextureObject *) mach64AllocTexObj(texObj); if (!t) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D"); return; } } /* Note, this will call mach64ChooseTextureFormat */ _mesa_store_teximage1d( ctx, target, level, internalFormat, width, border, format, type, pixels, packing, texObj, texImage ); mmesa->new_state |= MACH64_NEW_TEXTURE; } static void mach64TexSubImage1D( struct gl_context *ctx, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels, const struct gl_pixelstore_attrib *packing, struct gl_texture_object *texObj, struct gl_texture_image *texImage ) { mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); driTextureObject * t = (driTextureObject *) texObj->DriverData; assert( t ); /* this _should_ be true */ if ( t ) { driSwapOutTextureObject( t ); } else { t = (driTextureObject *) mach64AllocTexObj(texObj); if (!t) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage1D"); return; } } _mesa_store_texsubimage1d(ctx, target, level, xoffset, width, format, type, pixels, packing, texObj, texImage); mmesa->new_state |= MACH64_NEW_TEXTURE; } static void mach64TexImage2D( struct gl_context *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 ) { mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); driTextureObject * t = (driTextureObject *) texObj->DriverData; if ( t ) { driSwapOutTextureObject( t ); } else { t = (driTextureObject *) mach64AllocTexObj(texObj); if (!t) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D"); return; } } /* Note, this will call mach64ChooseTextureFormat */ _mesa_store_teximage2d( ctx, target, level, internalFormat, width, height, border, format, type, pixels, &ctx->Unpack, texObj, texImage ); mmesa->new_state |= MACH64_NEW_TEXTURE; } static void mach64TexSubImage2D( struct gl_context *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 ) { mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); driTextureObject * t = (driTextureObject *) texObj->DriverData; assert( t ); /* this _should_ be true */ if ( t ) { driSwapOutTextureObject( t ); } else { t = (driTextureObject *) mach64AllocTexObj(texObj); if (!t) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D"); return; } } _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width, height, format, type, pixels, packing, texObj, texImage); mmesa->new_state |= MACH64_NEW_TEXTURE; } /* ================================================================ * Device Driver API texture functions */ static void mach64DDTexEnv( struct gl_context *ctx, GLenum target, GLenum pname, const GLfloat *param ) { mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); #if 0 struct gl_texture_unit *texUnit; GLubyte c[4]; #endif if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { fprintf( stderr, "%s( %s )\n", __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) ); } switch ( pname ) { case GL_TEXTURE_ENV_MODE: FLUSH_BATCH( mmesa ); mmesa->new_state |= MACH64_NEW_TEXTURE | MACH64_NEW_ALPHA; break; #if 0 case GL_TEXTURE_ENV_COLOR: texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; CLAMPED_FLOAT_TO_UBYTE( c[0], texUnit->EnvColor[0] ); CLAMPED_FLOAT_TO_UBYTE( c[1], texUnit->EnvColor[1] ); CLAMPED_FLOAT_TO_UBYTE( c[2], texUnit->EnvColor[2] ); CLAMPED_FLOAT_TO_UBYTE( c[3], texUnit->EnvColor[3] ); mmesa->env_color = mach64PackColor( 32, c[0], c[1], c[2], c[3] ); if ( mmesa->setup.constant_color_c != mmesa->env_color ) { FLUSH_BATCH( mmesa ); mmesa->setup.constant_color_c = mmesa->env_color; mmesa->new_state |= MACH64_NEW_TEXTURE; /* More complex multitexture/multipass fallbacks for GL_BLEND * can be done later, but this allows a single pass GL_BLEND * in some cases (ie. Performer town demo). */ mmesa->blend_flags &= ~MACH64_BLEND_ENV_COLOR; if ( mmesa->env_color != 0x00000000 && mmesa->env_color != 0xff000000 && mmesa->env_color != 0x00ffffff && mmesa->env_color != 0xffffffff )) { mmesa->blend_flags |= MACH64_BLEND_ENV_COLOR; } } break; #endif default: return; } } static void mach64DDTexParameter( struct gl_context *ctx, GLenum target, struct gl_texture_object *tObj, GLenum pname, const GLfloat *params ) { mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); mach64TexObjPtr t = (mach64TexObjPtr)tObj->DriverData; if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { fprintf( stderr, "%s( %s )\n", __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) ); } if ( ( target != GL_TEXTURE_2D ) && ( target != GL_TEXTURE_1D ) ) { return; } if (!t) { t = mach64AllocTexObj(tObj); if (!t) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexParameter"); return; } } switch ( pname ) { case GL_TEXTURE_MIN_FILTER: case GL_TEXTURE_MAG_FILTER: if ( t->base.bound ) FLUSH_BATCH( mmesa ); mach64SetTexFilter( t, tObj->MinFilter, tObj->MagFilter ); break; case GL_TEXTURE_WRAP_S: case GL_TEXTURE_WRAP_T: if ( t->base.bound ) FLUSH_BATCH( mmesa ); mach64SetTexWrap( t, tObj->WrapS, tObj->WrapT ); break; case GL_TEXTURE_BORDER_COLOR: if ( t->base.bound ) FLUSH_BATCH( mmesa ); mach64SetTexBorderColor( t, tObj->BorderColor.f ); break; case GL_TEXTURE_BASE_LEVEL: /* From Radeon/Rage128: * 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. * * For mach64 we're only concerned with the base level * since that's the only texture we upload. */ if ( t->base.bound ) FLUSH_BATCH( mmesa ); driSwapOutTextureObject( (driTextureObject *) t ); break; default: return; } mmesa->new_state |= MACH64_NEW_TEXTURE; } static void mach64DDBindTexture( struct gl_context *ctx, GLenum target, struct gl_texture_object *tObj ) { mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); GLint unit = ctx->Texture.CurrentUnit; if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { fprintf( stderr, "%s( %p ) unit=%d\n", __FUNCTION__, tObj, unit ); } FLUSH_BATCH( mmesa ); if ( mmesa->CurrentTexObj[unit] ) { mmesa->CurrentTexObj[unit]->base.bound &= ~(1 << unit); mmesa->CurrentTexObj[unit] = NULL; } mmesa->new_state |= MACH64_NEW_TEXTURE; } static void mach64DDDeleteTexture( struct gl_context *ctx, struct gl_texture_object *tObj ) { mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); driTextureObject * t = (driTextureObject *) tObj->DriverData; if ( t ) { if ( t->bound && mmesa ) { FLUSH_BATCH( mmesa ); mmesa->new_state |= MACH64_NEW_TEXTURE; } driDestroyTextureObject( t ); /* Free mipmap images and the texture object itself */ _mesa_delete_texture_object(ctx, tObj); } } /** * Allocate a new texture object. * Called via ctx->Driver.NewTextureObject. * 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 * mach64NewTextureObject( struct gl_context *ctx, GLuint name, GLenum target ) { struct gl_texture_object *obj; obj = _mesa_new_texture_object(ctx, name, target); mach64AllocTexObj( obj ); return obj; } void mach64InitTextureFuncs( struct dd_function_table *functions ) { functions->TexEnv = mach64DDTexEnv; functions->ChooseTextureFormat = mach64ChooseTextureFormat; functions->TexImage1D = mach64TexImage1D; functions->TexSubImage1D = mach64TexSubImage1D; functions->TexImage2D = mach64TexImage2D; functions->TexSubImage2D = mach64TexSubImage2D; functions->TexParameter = mach64DDTexParameter; functions->BindTexture = mach64DDBindTexture; functions->NewTextureObject = mach64NewTextureObject; functions->DeleteTexture = mach64DDDeleteTexture; functions->IsTextureResident = driIsTextureResident; driInitTextureFormats(); }