| /* |
| * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. |
| * Copyright 2001-2003 S3 Graphics, Inc. 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, 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 |
| * VIA, S3 GRAPHICS, 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. |
| */ |
| |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| |
| #include "glheader.h" |
| #include "macros.h" |
| #include "mtypes.h" |
| #include "enums.h" |
| #include "colortab.h" |
| #include "convolve.h" |
| #include "context.h" |
| #include "mipmap.h" |
| #include "simple_list.h" |
| #include "texcompress.h" |
| #include "texformat.h" |
| #include "texobj.h" |
| #include "texstore.h" |
| |
| #include "mm.h" |
| #include "via_context.h" |
| #include "via_fb.h" |
| #include "via_tex.h" |
| #include "via_state.h" |
| #include "via_ioctl.h" |
| #include "via_3d_reg.h" |
| |
| static const struct gl_texture_format * |
| viaChooseTexFormat( GLcontext *ctx, GLint internalFormat, |
| GLenum format, GLenum type ) |
| { |
| struct via_context *vmesa = VIA_CONTEXT(ctx); |
| const GLboolean do32bpt = ( vmesa->viaScreen->bitsPerPixel == 32 |
| /* && vmesa->viaScreen->textureSize > 4*1024*1024 */ |
| ); |
| |
| |
| switch ( internalFormat ) { |
| case 4: |
| case GL_RGBA: |
| case GL_COMPRESSED_RGBA: |
| if ( format == GL_BGRA ) { |
| if ( type == GL_UNSIGNED_INT_8_8_8_8_REV || |
| type == GL_UNSIGNED_BYTE ) { |
| return &_mesa_texformat_argb8888; |
| } |
| else if ( type == GL_UNSIGNED_SHORT_4_4_4_4_REV ) { |
| return &_mesa_texformat_argb4444; |
| } |
| else if ( type == GL_UNSIGNED_SHORT_1_5_5_5_REV ) { |
| return &_mesa_texformat_argb1555; |
| } |
| } |
| else if ( type == GL_UNSIGNED_BYTE || |
| type == GL_UNSIGNED_INT_8_8_8_8_REV || |
| type == GL_UNSIGNED_INT_8_8_8_8 ) { |
| return &_mesa_texformat_argb8888; |
| } |
| return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444; |
| |
| case 3: |
| case GL_RGB: |
| case GL_COMPRESSED_RGB: |
| if ( format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5 ) { |
| return &_mesa_texformat_rgb565; |
| } |
| else if ( type == GL_UNSIGNED_BYTE ) { |
| return &_mesa_texformat_argb8888; |
| } |
| return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565; |
| |
| case GL_RGBA8: |
| case GL_RGB10_A2: |
| case GL_RGBA12: |
| case GL_RGBA16: |
| return &_mesa_texformat_argb8888; |
| |
| case GL_RGBA4: |
| case GL_RGBA2: |
| return &_mesa_texformat_argb4444; |
| |
| case GL_RGB5_A1: |
| return &_mesa_texformat_argb1555; |
| |
| case GL_RGB8: |
| case GL_RGB10: |
| case GL_RGB12: |
| case GL_RGB16: |
| return &_mesa_texformat_argb8888; |
| |
| case GL_RGB5: |
| case GL_RGB4: |
| case GL_R3_G3_B2: |
| return &_mesa_texformat_rgb565; |
| |
| case GL_ALPHA: |
| case GL_ALPHA4: |
| case GL_ALPHA8: |
| case GL_ALPHA12: |
| case GL_ALPHA16: |
| case GL_COMPRESSED_ALPHA: |
| return &_mesa_texformat_a8; |
| |
| case 1: |
| case GL_LUMINANCE: |
| case GL_LUMINANCE4: |
| case GL_LUMINANCE8: |
| case GL_LUMINANCE12: |
| case GL_LUMINANCE16: |
| case GL_COMPRESSED_LUMINANCE: |
| return &_mesa_texformat_l8; |
| |
| 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: |
| return &_mesa_texformat_al88; |
| |
| case GL_INTENSITY: |
| case GL_INTENSITY4: |
| case GL_INTENSITY8: |
| case GL_INTENSITY12: |
| case GL_INTENSITY16: |
| case GL_COMPRESSED_INTENSITY: |
| return &_mesa_texformat_i8; |
| |
| 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; |
| |
| case GL_COMPRESSED_RGB_FXT1_3DFX: |
| return &_mesa_texformat_rgb_fxt1; |
| case GL_COMPRESSED_RGBA_FXT1_3DFX: |
| return &_mesa_texformat_rgba_fxt1; |
| |
| case GL_RGB_S3TC: |
| case GL_RGB4_S3TC: |
| case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: |
| return &_mesa_texformat_rgb_dxt1; |
| |
| case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: |
| return &_mesa_texformat_rgba_dxt1; |
| |
| case GL_RGBA_S3TC: |
| case GL_RGBA4_S3TC: |
| case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: |
| return &_mesa_texformat_rgba_dxt3; |
| |
| case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: |
| return &_mesa_texformat_rgba_dxt5; |
| |
| 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_texformat_ci8; |
| |
| default: |
| fprintf(stderr, "unexpected texture format %s in %s\n", |
| _mesa_lookup_enum_by_nr(internalFormat), |
| __FUNCTION__); |
| return NULL; |
| } |
| |
| return NULL; /* never get here */ |
| } |
| |
| static int logbase2(int n) |
| { |
| GLint i = 1; |
| GLint log2 = 0; |
| |
| while (n > i) { |
| i *= 2; |
| log2++; |
| } |
| |
| return log2; |
| } |
| |
| static const char *get_memtype_name( GLint memType ) |
| { |
| static const char *names[] = { |
| "VIA_MEM_VIDEO", |
| "VIA_MEM_AGP", |
| "VIA_MEM_SYSTEM", |
| "VIA_MEM_MIXED", |
| "VIA_MEM_UNKNOWN" |
| }; |
| |
| return names[memType]; |
| } |
| |
| |
| static GLboolean viaMoveTexBuffers( struct via_context *vmesa, |
| struct via_tex_buffer **buffers, |
| GLuint nr, |
| GLint newMemType ) |
| { |
| struct via_tex_buffer *newTexBuf[VIA_MAX_TEXLEVELS]; |
| GLint i; |
| |
| if (VIA_DEBUG & DEBUG_TEXTURE) |
| fprintf(stderr, "%s to %s\n", |
| __FUNCTION__, |
| get_memtype_name(newMemType)); |
| |
| memset(newTexBuf, 0, sizeof(newTexBuf)); |
| |
| /* First do all the allocations (or fail): |
| */ |
| for (i = 0; i < nr; i++) { |
| if (buffers[i]->memType != newMemType) { |
| |
| /* Don't allow uploads in a thrash state. Should try and |
| * catch this earlier. |
| */ |
| if (vmesa->thrashing && newMemType != VIA_MEM_SYSTEM) |
| goto cleanup; |
| |
| newTexBuf[i] = via_alloc_texture(vmesa, |
| buffers[i]->size, |
| newMemType); |
| if (!newTexBuf[i]) |
| goto cleanup; |
| } |
| } |
| |
| |
| /* Now copy all the image data and free the old texture memory. |
| */ |
| for (i = 0; i < nr; i++) { |
| if (newTexBuf[i]) { |
| memcpy(newTexBuf[i]->bufAddr, |
| buffers[i]->bufAddr, |
| buffers[i]->size); |
| |
| newTexBuf[i]->image = buffers[i]->image; |
| newTexBuf[i]->image->texMem = newTexBuf[i]; |
| newTexBuf[i]->image->image.Data = newTexBuf[i]->bufAddr; |
| via_free_texture(vmesa, buffers[i]); |
| } |
| } |
| |
| if (VIA_DEBUG & DEBUG_TEXTURE) |
| fprintf(stderr, "%s - success\n", __FUNCTION__); |
| |
| return GL_TRUE; |
| |
| cleanup: |
| /* Release any allocations made prior to failure: |
| */ |
| if (VIA_DEBUG & DEBUG_TEXTURE) |
| fprintf(stderr, "%s - failed\n", __FUNCTION__); |
| |
| for (i = 0; i < nr; i++) { |
| if (newTexBuf[i]) { |
| via_free_texture(vmesa, newTexBuf[i]); |
| } |
| } |
| |
| return GL_FALSE; |
| } |
| |
| |
| static GLboolean viaMoveTexObject( struct via_context *vmesa, |
| struct via_texture_object *viaObj, |
| GLint newMemType ) |
| { |
| struct via_texture_image **viaImage = |
| (struct via_texture_image **)&viaObj->obj.Image[0][0]; |
| struct via_tex_buffer *buffers[VIA_MAX_TEXLEVELS]; |
| GLuint i, nr = 0; |
| |
| for (i = viaObj->firstLevel; i <= viaObj->lastLevel; i++) |
| buffers[nr++] = viaImage[i]->texMem; |
| |
| if (viaMoveTexBuffers( vmesa, &buffers[0], nr, newMemType )) { |
| viaObj->memType = newMemType; |
| return GL_TRUE; |
| } |
| |
| return GL_FALSE; |
| } |
| |
| |
| |
| static GLboolean viaSwapInTexObject( struct via_context *vmesa, |
| struct via_texture_object *viaObj ) |
| { |
| const struct via_texture_image *baseImage = |
| (struct via_texture_image *)viaObj->obj.Image[0][viaObj->obj.BaseLevel]; |
| |
| if (VIA_DEBUG & DEBUG_TEXTURE) |
| fprintf(stderr, "%s\n", __FUNCTION__); |
| |
| if (baseImage->texMem->memType != VIA_MEM_SYSTEM) |
| return viaMoveTexObject( vmesa, viaObj, baseImage->texMem->memType ); |
| |
| return (viaMoveTexObject( vmesa, viaObj, VIA_MEM_AGP ) || |
| viaMoveTexObject( vmesa, viaObj, VIA_MEM_VIDEO )); |
| } |
| |
| |
| /* This seems crude, but it asks a fairly pertinent question and gives |
| * an accurate answer: |
| */ |
| static GLboolean viaIsTexMemLow( struct via_context *vmesa, |
| GLuint heap ) |
| { |
| struct via_tex_buffer *buf = via_alloc_texture(vmesa, 512 * 1024, heap ); |
| if (!buf) |
| return GL_TRUE; |
| |
| via_free_texture(vmesa, buf); |
| return GL_FALSE; |
| } |
| |
| |
| /* Speculatively move texture images which haven't been used in a |
| * while back to system memory. |
| * |
| * TODO: only do this when texture memory is low. |
| * |
| * TODO: use dma. |
| * |
| * TODO: keep the fb/agp version hanging around and use the local |
| * version as backing store, so re-upload might be avoided. |
| * |
| * TODO: do this properly in the kernel... |
| */ |
| GLboolean viaSwapOutWork( struct via_context *vmesa ) |
| { |
| struct via_tex_buffer *s, *tmp; |
| GLuint done = 0; |
| GLuint heap, target; |
| |
| if (VIA_DEBUG & DEBUG_TEXTURE) |
| fprintf(stderr, "%s VID %d AGP %d SYS %d\n", __FUNCTION__, |
| vmesa->total_alloc[VIA_MEM_VIDEO], |
| vmesa->total_alloc[VIA_MEM_AGP], |
| vmesa->total_alloc[VIA_MEM_SYSTEM]); |
| |
| |
| for (heap = VIA_MEM_VIDEO; heap <= VIA_MEM_AGP; heap++) { |
| GLuint nr = 0, sz = 0; |
| |
| if (vmesa->thrashing) { |
| if (VIA_DEBUG & DEBUG_TEXTURE) |
| fprintf(stderr, "Heap %d: trash flag\n", heap); |
| target = 1*1024*1024; |
| } |
| else if (viaIsTexMemLow(vmesa, heap)) { |
| if (VIA_DEBUG & DEBUG_TEXTURE) |
| fprintf(stderr, "Heap %d: low memory\n", heap); |
| target = 64*1024; |
| } |
| else { |
| if (VIA_DEBUG & DEBUG_TEXTURE) |
| fprintf(stderr, "Heap %d: nothing to do\n", heap); |
| continue; |
| } |
| |
| foreach_s( s, tmp, &vmesa->tex_image_list[heap] ) { |
| if (s->lastUsed < vmesa->lastSwap[1]) { |
| struct via_texture_object *viaObj = |
| (struct via_texture_object *) s->image->image.TexObject; |
| |
| if (VIA_DEBUG & DEBUG_TEXTURE) |
| fprintf(stderr, |
| "back copy tex sz %d, lastUsed %d lastSwap %d\n", |
| s->size, s->lastUsed, vmesa->lastSwap[1]); |
| |
| if (viaMoveTexBuffers( vmesa, &s, 1, VIA_MEM_SYSTEM )) { |
| viaObj->memType = VIA_MEM_MIXED; |
| done += s->size; |
| } |
| else { |
| if (VIA_DEBUG & DEBUG_TEXTURE) |
| fprintf(stderr, "Failed to back copy texture!\n"); |
| sz += s->size; |
| } |
| } |
| else { |
| nr ++; |
| sz += s->size; |
| } |
| |
| if (done > target) { |
| vmesa->thrashing = GL_FALSE; /* might not get set otherwise? */ |
| return GL_TRUE; |
| } |
| } |
| |
| assert(sz == vmesa->total_alloc[heap]); |
| |
| if (VIA_DEBUG & DEBUG_TEXTURE) |
| fprintf(stderr, "Heap %d: nr %d tot sz %d\n", heap, nr, sz); |
| } |
| |
| |
| return done != 0; |
| } |
| |
| |
| |
| /* Basically, just collect the image dimensions and addresses for each |
| * image and update the texture object state accordingly. |
| */ |
| static GLboolean viaSetTexImages(GLcontext *ctx, |
| struct gl_texture_object *texObj) |
| { |
| struct via_context *vmesa = VIA_CONTEXT(ctx); |
| struct via_texture_object *viaObj = (struct via_texture_object *)texObj; |
| const struct via_texture_image *baseImage = |
| (struct via_texture_image *)texObj->Image[0][texObj->BaseLevel]; |
| GLint firstLevel, lastLevel, numLevels; |
| GLuint texFormat; |
| GLint w, h, p; |
| GLint i, j = 0, k = 0, l = 0, m = 0; |
| GLuint texBase; |
| GLuint basH = 0; |
| GLuint widthExp = 0; |
| GLuint heightExp = 0; |
| |
| switch (baseImage->image.TexFormat->MesaFormat) { |
| case MESA_FORMAT_ARGB8888: |
| texFormat = HC_HTXnFM_ARGB8888; |
| break; |
| case MESA_FORMAT_ARGB4444: |
| texFormat = HC_HTXnFM_ARGB4444; |
| break; |
| case MESA_FORMAT_RGB565: |
| texFormat = HC_HTXnFM_RGB565; |
| break; |
| case MESA_FORMAT_ARGB1555: |
| texFormat = HC_HTXnFM_ARGB1555; |
| break; |
| case MESA_FORMAT_RGB888: |
| texFormat = HC_HTXnFM_ARGB0888; |
| break; |
| case MESA_FORMAT_L8: |
| texFormat = HC_HTXnFM_L8; |
| break; |
| case MESA_FORMAT_I8: |
| texFormat = HC_HTXnFM_T8; |
| break; |
| case MESA_FORMAT_CI8: |
| texFormat = HC_HTXnFM_Index8; |
| break; |
| case MESA_FORMAT_AL88: |
| texFormat = HC_HTXnFM_AL88; |
| break; |
| case MESA_FORMAT_A8: |
| texFormat = HC_HTXnFM_A8; |
| break; |
| default: |
| _mesa_problem(vmesa->glCtx, "Bad texture format in viaSetTexImages"); |
| return GL_FALSE; |
| } |
| |
| /* 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. |
| */ |
| if (texObj->MinFilter == GL_LINEAR || texObj->MinFilter == GL_NEAREST) { |
| firstLevel = lastLevel = texObj->BaseLevel; |
| } |
| else { |
| firstLevel = texObj->BaseLevel + (GLint)(texObj->MinLod + 0.5); |
| firstLevel = MAX2(firstLevel, texObj->BaseLevel); |
| lastLevel = texObj->BaseLevel + (GLint)(texObj->MaxLod + 0.5); |
| lastLevel = MAX2(lastLevel, texObj->BaseLevel); |
| lastLevel = MIN2(lastLevel, texObj->BaseLevel + baseImage->image.MaxLog2); |
| lastLevel = MIN2(lastLevel, texObj->MaxLevel); |
| lastLevel = MAX2(firstLevel, lastLevel); /* need at least one level */ |
| } |
| |
| numLevels = lastLevel - firstLevel + 1; |
| |
| /* The hardware supports only 10 mipmap levels; ignore higher levels. |
| */ |
| if ((numLevels > 10) && (ctx->Const.MaxTextureLevels > 10)) { |
| lastLevel -= numLevels - 10; |
| numLevels = 10; |
| } |
| |
| /* save these values, check if they effect the residency of the |
| * texture: |
| */ |
| if (viaObj->firstLevel != firstLevel || |
| viaObj->lastLevel != lastLevel) { |
| viaObj->firstLevel = firstLevel; |
| viaObj->lastLevel = lastLevel; |
| viaObj->memType = VIA_MEM_MIXED; |
| } |
| |
| if (VIA_DEBUG & DEBUG_TEXTURE & 0) |
| fprintf(stderr, "%s, current memType: %s\n", |
| __FUNCTION__, |
| get_memtype_name(viaObj->memType)); |
| |
| |
| if (viaObj->memType == VIA_MEM_MIXED || |
| viaObj->memType == VIA_MEM_SYSTEM) { |
| if (!viaSwapInTexObject(vmesa, viaObj)) { |
| if (VIA_DEBUG & DEBUG_TEXTURE) |
| if (!vmesa->thrashing) |
| fprintf(stderr, "Thrashing flag set for frame %d\n", |
| vmesa->swap_count); |
| vmesa->thrashing = GL_TRUE; |
| return GL_FALSE; |
| } |
| } |
| |
| if (viaObj->memType == VIA_MEM_AGP) |
| viaObj->regTexFM = (HC_SubA_HTXnFM << 24) | HC_HTXnLoc_AGP | texFormat; |
| else |
| viaObj->regTexFM = (HC_SubA_HTXnFM << 24) | HC_HTXnLoc_Local | texFormat; |
| |
| |
| for (i = 0; i < numLevels; i++) { |
| struct via_texture_image *viaImage = |
| (struct via_texture_image *)texObj->Image[0][firstLevel + i]; |
| |
| w = viaImage->image.WidthLog2; |
| h = viaImage->image.HeightLog2; |
| p = viaImage->pitchLog2; |
| |
| assert(viaImage->texMem->memType == viaObj->memType); |
| |
| texBase = viaImage->texMem->texBase; |
| if (!texBase) { |
| if (VIA_DEBUG & DEBUG_TEXTURE) |
| fprintf(stderr, "%s: no texBase[%d]\n", __FUNCTION__, i); |
| return GL_FALSE; |
| } |
| |
| /* Image has to remain resident until the coming fence is retired. |
| */ |
| move_to_head( &vmesa->tex_image_list[viaImage->texMem->memType], |
| viaImage->texMem ); |
| viaImage->texMem->lastUsed = vmesa->lastBreadcrumbWrite; |
| |
| |
| viaObj->regTexBaseAndPitch[i].baseL = |
| ((HC_SubA_HTXnL0BasL + i) << 24) | (texBase & 0xFFFFFF); |
| |
| viaObj->regTexBaseAndPitch[i].pitchLog2 = |
| ((HC_SubA_HTXnL0Pit + i) << 24) | (p << 20); |
| |
| |
| /* The base high bytes for each 3 levels are packed |
| * together into one register: |
| */ |
| j = i / 3; |
| k = 3 - (i % 3); |
| basH |= ((texBase & 0xFF000000) >> (k << 3)); |
| if (k == 1) { |
| viaObj->regTexBaseH[j] = ((j + HC_SubA_HTXnL012BasH) << 24) | basH; |
| basH = 0; |
| } |
| |
| /* Likewise, sets of 6 log2width and log2height values are |
| * packed into individual registers: |
| */ |
| l = i / 6; |
| m = i % 6; |
| widthExp |= (((GLuint)w & 0xF) << (m << 2)); |
| heightExp |= (((GLuint)h & 0xF) << (m << 2)); |
| if (m == 5) { |
| viaObj->regTexWidthLog2[l] = |
| (l + HC_SubA_HTXnL0_5WE) << 24 | widthExp; |
| viaObj->regTexHeightLog2[l] = |
| (l + HC_SubA_HTXnL0_5HE) << 24 | heightExp; |
| widthExp = 0; |
| heightExp = 0; |
| } |
| if (w) w--; |
| if (h) h--; |
| if (p) p--; |
| } |
| |
| if (k != 1) { |
| viaObj->regTexBaseH[j] = ((j + HC_SubA_HTXnL012BasH) << 24) | basH; |
| } |
| if (m != 5) { |
| viaObj->regTexWidthLog2[l] = (l + HC_SubA_HTXnL0_5WE) << 24 | widthExp; |
| viaObj->regTexHeightLog2[l] = (l + HC_SubA_HTXnL0_5HE) << 24 | heightExp; |
| } |
| |
| return GL_TRUE; |
| } |
| |
| |
| GLboolean viaUpdateTextureState( GLcontext *ctx ) |
| { |
| struct gl_texture_unit *texUnit = ctx->Texture.Unit; |
| GLuint i; |
| |
| for (i = 0; i < 2; i++) { |
| if (texUnit[i]._ReallyEnabled == TEXTURE_2D_BIT || |
| texUnit[i]._ReallyEnabled == TEXTURE_1D_BIT) { |
| |
| if (!viaSetTexImages(ctx, texUnit[i]._Current)) |
| return GL_FALSE; |
| } |
| else if (texUnit[i]._ReallyEnabled) { |
| return GL_FALSE; |
| } |
| } |
| |
| return GL_TRUE; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| static void viaTexImage(GLcontext *ctx, |
| GLint dims, |
| GLenum target, GLint level, |
| GLint internalFormat, |
| GLint width, GLint height, GLint border, |
| GLenum format, GLenum type, const void *pixels, |
| const struct gl_pixelstore_attrib *packing, |
| struct gl_texture_object *texObj, |
| struct gl_texture_image *texImage) |
| { |
| struct via_context *vmesa = VIA_CONTEXT(ctx); |
| GLint postConvWidth = width; |
| GLint postConvHeight = height; |
| GLint texelBytes, sizeInBytes; |
| struct via_texture_object *viaObj = (struct via_texture_object *)texObj; |
| struct via_texture_image *viaImage = (struct via_texture_image *)texImage; |
| int heaps[3], nheaps, i; |
| |
| if (!is_empty_list(&vmesa->freed_tex_buffers)) { |
| viaCheckBreadcrumb(vmesa, 0); |
| via_release_pending_textures(vmesa); |
| } |
| |
| if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) { |
| _mesa_adjust_image_for_convolution(ctx, dims, &postConvWidth, |
| &postConvHeight); |
| } |
| |
| /* choose the texture format */ |
| texImage->TexFormat = viaChooseTexFormat(ctx, internalFormat, |
| format, type); |
| |
| assert(texImage->TexFormat); |
| |
| if (dims == 1) { |
| texImage->FetchTexelc = texImage->TexFormat->FetchTexel1D; |
| texImage->FetchTexelf = texImage->TexFormat->FetchTexel1Df; |
| } |
| else { |
| texImage->FetchTexelc = texImage->TexFormat->FetchTexel2D; |
| texImage->FetchTexelf = texImage->TexFormat->FetchTexel2Df; |
| } |
| texelBytes = texImage->TexFormat->TexelBytes; |
| |
| if (texelBytes == 0) { |
| /* compressed format */ |
| texImage->IsCompressed = GL_TRUE; |
| texImage->CompressedSize = |
| ctx->Driver.CompressedTextureSize(ctx, texImage->Width, |
| texImage->Height, texImage->Depth, |
| texImage->TexFormat->MesaFormat); |
| } |
| |
| /* Minimum pitch of 32 bytes */ |
| if (postConvWidth * texelBytes < 32) { |
| postConvWidth = 32 / texelBytes; |
| texImage->RowStride = postConvWidth; |
| } |
| |
| assert(texImage->RowStride == postConvWidth); |
| viaImage->pitchLog2 = logbase2(postConvWidth * texelBytes); |
| |
| /* allocate memory */ |
| if (texImage->IsCompressed) |
| sizeInBytes = texImage->CompressedSize; |
| else |
| sizeInBytes = postConvWidth * postConvHeight * texelBytes; |
| |
| |
| /* Attempt to allocate texture memory directly, otherwise use main |
| * memory and this texture will always be a fallback. FIXME! |
| * |
| * TODO: make room in agp if this fails. |
| * TODO: use fb ram for textures as well. |
| */ |
| |
| |
| switch (viaObj->memType) { |
| case VIA_MEM_UNKNOWN: |
| heaps[0] = VIA_MEM_AGP; |
| heaps[1] = VIA_MEM_VIDEO; |
| heaps[2] = VIA_MEM_SYSTEM; |
| nheaps = 3; |
| break; |
| case VIA_MEM_AGP: |
| case VIA_MEM_VIDEO: |
| heaps[0] = viaObj->memType; |
| heaps[1] = VIA_MEM_SYSTEM; |
| nheaps = 2; |
| break; |
| case VIA_MEM_MIXED: |
| case VIA_MEM_SYSTEM: |
| default: |
| heaps[0] = VIA_MEM_SYSTEM; |
| nheaps = 1; |
| break; |
| } |
| |
| for (i = 0; i < nheaps && !viaImage->texMem; i++) { |
| if (VIA_DEBUG & DEBUG_TEXTURE) |
| fprintf(stderr, "try %s (obj %s)\n", get_memtype_name(heaps[i]), |
| get_memtype_name(viaObj->memType)); |
| viaImage->texMem = via_alloc_texture(vmesa, sizeInBytes, heaps[i]); |
| } |
| |
| if (!viaImage->texMem) { |
| _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); |
| return; |
| } |
| |
| if (VIA_DEBUG & DEBUG_TEXTURE) |
| fprintf(stderr, "upload %d bytes to %s\n", sizeInBytes, |
| get_memtype_name(viaImage->texMem->memType)); |
| |
| viaImage->texMem->image = viaImage; |
| texImage->Data = viaImage->texMem->bufAddr; |
| |
| if (viaObj->memType == VIA_MEM_UNKNOWN) |
| viaObj->memType = viaImage->texMem->memType; |
| else if (viaObj->memType != viaImage->texMem->memType) |
| viaObj->memType = VIA_MEM_MIXED; |
| |
| if (VIA_DEBUG & DEBUG_TEXTURE) |
| fprintf(stderr, "%s, obj %s, image : %s\n", |
| __FUNCTION__, |
| get_memtype_name(viaObj->memType), |
| get_memtype_name(viaImage->texMem->memType)); |
| |
| vmesa->clearTexCache = 1; |
| |
| pixels = _mesa_validate_pbo_teximage(ctx, dims, width, height, 1, |
| format, type, |
| pixels, packing, "glTexImage"); |
| if (!pixels) { |
| /* Note: we check for a NULL image pointer here, _after_ we allocated |
| * memory for the texture. That's what the GL spec calls for. |
| */ |
| return; |
| } |
| else { |
| GLint dstRowStride; |
| GLboolean success; |
| if (texImage->IsCompressed) { |
| dstRowStride = _mesa_compressed_row_stride(texImage->TexFormat->MesaFormat, width); |
| } |
| else { |
| dstRowStride = postConvWidth * texImage->TexFormat->TexelBytes; |
| } |
| ASSERT(texImage->TexFormat->StoreImage); |
| success = texImage->TexFormat->StoreImage(ctx, dims, |
| texImage->_BaseFormat, |
| texImage->TexFormat, |
| texImage->Data, |
| 0, 0, 0, /* dstX/Y/Zoffset */ |
| dstRowStride, |
| texImage->ImageOffsets, |
| width, height, 1, |
| format, type, pixels, packing); |
| if (!success) { |
| _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); |
| } |
| } |
| |
| /* GL_SGIS_generate_mipmap */ |
| if (level == texObj->BaseLevel && texObj->GenerateMipmap) { |
| _mesa_generate_mipmap(ctx, target, texObj); |
| } |
| |
| _mesa_unmap_teximage_pbo(ctx, packing); |
| } |
| |
| static void viaTexImage2D(GLcontext *ctx, |
| GLenum target, GLint level, |
| GLint internalFormat, |
| GLint width, GLint height, GLint border, |
| GLenum format, GLenum type, const void *pixels, |
| const struct gl_pixelstore_attrib *packing, |
| struct gl_texture_object *texObj, |
| struct gl_texture_image *texImage) |
| { |
| viaTexImage( ctx, 2, target, level, |
| internalFormat, width, height, border, |
| format, type, pixels, |
| packing, texObj, texImage ); |
| } |
| |
| static void viaTexSubImage2D(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) |
| { |
| struct via_context *vmesa = VIA_CONTEXT(ctx); |
| |
| viaWaitIdle(vmesa, GL_TRUE); |
| vmesa->clearTexCache = 1; |
| |
| _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width, |
| height, format, type, pixels, packing, texObj, |
| texImage); |
| } |
| |
| static void viaTexImage1D(GLcontext *ctx, |
| GLenum target, GLint level, |
| GLint internalFormat, |
| GLint width, GLint border, |
| GLenum format, GLenum type, const void *pixels, |
| const struct gl_pixelstore_attrib *packing, |
| struct gl_texture_object *texObj, |
| struct gl_texture_image *texImage) |
| { |
| viaTexImage( ctx, 1, target, level, |
| internalFormat, width, 1, border, |
| format, type, pixels, |
| packing, texObj, texImage ); |
| } |
| |
| static void viaTexSubImage1D(GLcontext *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) |
| { |
| struct via_context *vmesa = VIA_CONTEXT(ctx); |
| |
| viaWaitIdle(vmesa, GL_TRUE); |
| vmesa->clearTexCache = 1; |
| |
| _mesa_store_texsubimage1d(ctx, target, level, xoffset, width, |
| format, type, pixels, packing, texObj, |
| texImage); |
| } |
| |
| |
| |
| static GLboolean viaIsTextureResident(GLcontext *ctx, |
| struct gl_texture_object *texObj) |
| { |
| struct via_texture_object *viaObj = |
| (struct via_texture_object *)texObj; |
| |
| return (viaObj->memType == VIA_MEM_AGP || |
| viaObj->memType == VIA_MEM_VIDEO); |
| } |
| |
| |
| |
| static struct gl_texture_image *viaNewTextureImage( GLcontext *ctx ) |
| { |
| (void) ctx; |
| return (struct gl_texture_image *)CALLOC_STRUCT(via_texture_image); |
| } |
| |
| |
| static struct gl_texture_object *viaNewTextureObject( GLcontext *ctx, |
| GLuint name, |
| GLenum target ) |
| { |
| struct via_texture_object *obj = CALLOC_STRUCT(via_texture_object); |
| |
| _mesa_initialize_texture_object(&obj->obj, name, target); |
| (void) ctx; |
| |
| obj->memType = VIA_MEM_UNKNOWN; |
| |
| return &obj->obj; |
| } |
| |
| |
| static void viaFreeTextureImageData( GLcontext *ctx, |
| struct gl_texture_image *texImage ) |
| { |
| struct via_context *vmesa = VIA_CONTEXT(ctx); |
| struct via_texture_image *image = (struct via_texture_image *)texImage; |
| |
| if (image->texMem) { |
| via_free_texture(vmesa, image->texMem); |
| image->texMem = NULL; |
| } |
| |
| texImage->Data = NULL; |
| } |
| |
| |
| |
| |
| void viaInitTextureFuncs(struct dd_function_table * functions) |
| { |
| functions->ChooseTextureFormat = viaChooseTexFormat; |
| functions->TexImage1D = viaTexImage1D; |
| functions->TexImage2D = viaTexImage2D; |
| functions->TexSubImage1D = viaTexSubImage1D; |
| functions->TexSubImage2D = viaTexSubImage2D; |
| |
| functions->NewTextureObject = viaNewTextureObject; |
| functions->NewTextureImage = viaNewTextureImage; |
| functions->DeleteTexture = _mesa_delete_texture_object; |
| functions->FreeTexImageData = viaFreeTextureImageData; |
| |
| #if 0 && defined( USE_SSE_ASM ) |
| /* |
| * XXX this code is disabled for now because the via_sse_memcpy() |
| * routine causes segfaults with flightgear. |
| * See Mesa3d-dev mail list messages from 7/15/2005 for details. |
| * Note that this function is currently disabled in via_tris.c too. |
| */ |
| if (getenv("VIA_NO_SSE")) |
| functions->TextureMemCpy = _mesa_memcpy; |
| else |
| functions->TextureMemCpy = via_sse_memcpy; |
| #else |
| functions->TextureMemCpy = _mesa_memcpy; |
| #endif |
| |
| functions->UpdateTexturePalette = 0; |
| functions->IsTextureResident = viaIsTextureResident; |
| } |
| |
| |