Search
lxdream.org :: lxdream/src/pvr2/texcache.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/texcache.c
changeset 103:9b9cfc5855e0
next107:e576dd36073a
author nkeynes
date Mon Mar 13 12:39:07 2006 +0000 (14 years ago)
permissions -rw-r--r--
last change More rendering work in progress. Almost there now...
view annotate diff log raw
     1 /**
     2  * $Id: texcache.c,v 1.1 2006-03-13 12:39:07 nkeynes Exp $
     3  *
     4  * Texture cache. Responsible for maintaining a working set of OpenGL 
     5  * textures. 
     6  *
     7  *
     8  * Copyright (c) 2005 Nathan Keynes.
     9  *
    10  * This program is free software; you can redistribute it and/or modify
    11  * it under the terms of the GNU General Public License as published by
    12  * the Free Software Foundation; either version 2 of the License, or
    13  * (at your option) any later version.
    14  *
    15  * This program is distributed in the hope that it will be useful,
    16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    18  * GNU General Public License for more details.
    19  */
    21 #include <assert.h>
    22 #include "pvr2/pvr2.h"
    24 /** Specifies the maximum number of OpenGL
    25  * textures we're willing to have open at a time. If more are
    26  * needed, textures will be evicted in LRU order.
    27  */
    28 #define MAX_TEXTURES 64
    30 /**
    31  * Data structure:
    32  *
    33  * Main operations:
    34  *    find entry by texture_addr
    35  *    add new entry
    36  *    move entry to tail of lru list
    37  *    remove entry
    38  */
    40 typedef signed short texcache_entry_index;
    41 #define EMPTY_ENTRY -1
    43 static texcache_entry_index texcache_free_ptr;
    44 static GLuint texcache_free_list[MAX_TEXTURES];
    46 typedef struct texcache_entry {
    47     uint32_t texture_addr;
    48     int width, height, mode;
    49     GLuint texture_id;
    50     texcache_entry_index next;
    51     uint32_t lru_count;
    52 } *texcache_entry_t;
    54 static uint8_t texcache_page_lookup[PVR2_RAM_PAGES];
    55 static uint32_t texcache_active_ptr;
    56 static uint32_t texcache_ref_counter;
    57 static struct texcache_entry texcache_active_list[MAX_TEXTURES];
    59 /**
    60  * Initialize the texture cache. Note that the GL context must have been
    61  * initialized before calling this function.
    62  */
    63 void texcache_init( )
    64 {
    65     int i;
    66     GLuint texids[MAX_TEXTURES];
    67     glGenTextures( MAX_TEXTURES, texids );
    68     for( i=0; i<PVR2_RAM_PAGES; i++ ) {
    69 	texcache_page_lookup[i] = EMPTY_ENTRY;
    70     }
    71     for( i=0; i<MAX_TEXTURES; i++ ) {
    72 	texcache_active_list[i].texture_id = texids[i];
    73 	texcache_free_list[i] = i;
    74     }
    75     texcache_free_ptr = 0;
    76     texcache_ref_counter = 0;
    77 }
    79 /**
    80  * Flush all textures from the cache, returning them to the free list.
    81  */
    82 void texcache_flush( )
    83 {
    84     int i;
    85     /* clear structures */
    86     for( i=0; i<PVR2_RAM_PAGES; i++ ) {
    87 	texcache_page_lookup[i] = EMPTY_ENTRY;
    88     }
    89     for( i=0; i<MAX_TEXTURES; i++ ) {
    90 	texcache_free_list[i] = i;
    91     }
    92     texcache_free_ptr = 0;
    93     texcache_ref_counter = 0;
    94 }
    96 /**
    97  * Flush all textures and delete. The cache will be non-functional until
    98  * the next call to texcache_init(). This would typically be done if
    99  * switching GL targets.
   100  */    
   101 void texcache_shutdown( )
   102 {
   103     GLuint texids[MAX_TEXTURES];
   104     int i;
   105     texcache_flush();
   107     for( i=0; i<MAX_TEXTURES; i++ ) {
   108 	texids[i] = texcache_active_list[i].texture_id;
   109     }
   110     glDeleteTextures( MAX_TEXTURES, texids );
   111 }
   113 /**
   114  * Evict all textures contained in the page identified by a texture address.
   115  */
   116 void texcache_invalidate_page( uint32_t texture_addr ) {
   117     uint32_t texture_page = texture_addr >> 12;
   118     texcache_entry_index idx = texcache_page_lookup[texture_page];
   119     if( idx == EMPTY_ENTRY )
   120 	return;
   121     assert( texcache_free_ptr > 0 );
   122     do {
   123 	texcache_entry_t entry = &texcache_active_list[idx];	
   124 	/* release entry */
   125 	texcache_free_ptr--;
   126 	texcache_free_list[texcache_free_ptr] = idx;
   127 	idx = entry->next;
   128 	entry->next = EMPTY_ENTRY;
   129     } while( idx != EMPTY_ENTRY );
   130     texcache_page_lookup[texture_page] = EMPTY_ENTRY;
   131 }
   133 /**
   134  * Evict a single texture from the cache.
   135  * @return the slot of the evicted texture.
   136  */
   137 static texcache_entry_index texcache_evict( void )
   138 {
   139     /* Full table scan - take over the entry with the lowest lru value */
   140     texcache_entry_index slot = 0;
   141     int lru_value = texcache_active_list[0].lru_count;
   142     int i;
   143     for( i=1; i<MAX_TEXTURES; i++ ) {
   144 	/* FIXME: account for rollover */
   145 	if( texcache_active_list[i].lru_count < lru_value ) {
   146 	    slot = i;
   147 	    lru_value = texcache_active_list[i].lru_count;
   148 	}
   149     }
   151     /* Remove the selected slot from the lookup table */
   152     uint32_t evict_page = texcache_active_list[slot].texture_addr;
   153     texcache_entry_index replace_next = texcache_active_list[slot].next;
   154     texcache_active_list[slot].next = EMPTY_ENTRY; /* Just for safety */
   155     if( texcache_page_lookup[evict_page] == slot ) {
   156 	texcache_page_lookup[evict_page] = replace_next;
   157     } else {
   158 	texcache_entry_index idx = texcache_page_lookup[evict_page];
   159 	texcache_entry_index next;
   160 	do {
   161 	    next = texcache_active_list[idx].next;
   162 	    if( next == slot ) {
   163 		texcache_active_list[idx].next = replace_next;
   164 		break;
   165 	    }
   166 	    idx = next;
   167 	} while( next != EMPTY_ENTRY );
   168     }
   169     return slot;
   170 }
   172 /**
   173  * Load texture data from the given address and parameters into the currently
   174  * bound OpenGL texture.
   175  */
   176 static texcache_load_texture( uint32_t texture_addr, int width, int height,
   177 			      int mode ) {
   178     uint32_t bytes = width * height;
   179     int bpp = 2;
   180     GLint intFormat, format, type;
   181     switch( mode & PVR2_TEX_FORMAT_MASK ) {
   182     case PVR2_TEX_FORMAT_ARGB1555:
   183 	bytes <<= 1;
   184 	intFormat = GL_RGB5_A1;
   185 	format = GL_RGBA;
   186 	type = GL_UNSIGNED_SHORT_5_5_5_1;
   187 	break;
   188     case PVR2_TEX_FORMAT_RGB565:
   189 	bytes <<= 1;
   190 	intFormat = GL_RGBA;
   191 	format = GL_RGBA;
   192 	type = GL_UNSIGNED_SHORT_5_6_5;
   193 	break;
   194     case PVR2_TEX_FORMAT_ARGB4444:
   195 	bytes <<= 1;
   196 	intFormat = GL_RGBA4;
   197 	format = GL_RGBA;
   198 	type = GL_UNSIGNED_SHORT_4_4_4_4;
   199 	break;
   200     case PVR2_TEX_FORMAT_YUV422:
   201 	ERROR( "YUV textures not supported" );
   202 	break;
   203     case PVR2_TEX_FORMAT_BUMPMAP:
   204 	ERROR( "Bumpmap not supported" );
   205 	break;
   206     case PVR2_TEX_FORMAT_IDX4:
   207 	/* Supported? */
   208 	bytes >>= 1;
   209 	intFormat = GL_INTENSITY4;
   210 	format = GL_COLOR_INDEX;
   211 	type = GL_UNSIGNED_BYTE;
   212 	bpp = 0;
   213 	break;
   214     case PVR2_TEX_FORMAT_IDX8:
   215 	intFormat = GL_INTENSITY8;
   216 	format = GL_COLOR_INDEX;
   217 	type = GL_UNSIGNED_BYTE;
   218 	bpp = 1;
   219 	break;
   220     }
   222     unsigned char data[bytes];
   223     /* load data from image, detwiddling/uncompressing as required */
   224     if( PVR2_TEX_IS_COMPRESSED(mode) ) {
   225 	ERROR( "VQ Compression not supported" );
   226     } else {
   227 	pvr2_vram64_read( &data, texture_addr, bytes );
   228 	if( PVR2_TEX_IS_TWIDDLED(mode) ) {
   229 	    /* Untwiddle */
   230 	}
   231     }
   232     /* Pass to GL */
   233     glTexImage2D( GL_TEXTURE_2D, 0, intFormat, width, height, 0, format, type,
   234 		  data );
   235 }
   237 /**
   238  * Return a texture ID for the texture specified at the supplied address
   239  * and given parameters (the same sequence of bytes could in theory have
   240  * multiple interpretations). We use the texture address as the primary
   241  * index, but allow for multiple instances at each address. The texture
   242  * will be bound to the GL_TEXTURE_2D target before being returned.
   243  * 
   244  * If the texture has already been bound, return the ID to which it was
   245  * bound. Otherwise obtain an unused texture ID and set it up appropriately.
   246  */
   247 GLuint texcache_get_texture( uint32_t texture_addr, int width, int height,
   248 			     int mode )
   249 {
   250     uint32_t texture_page = texture_addr >> 12;
   251     texcache_entry_index idx = texcache_page_lookup[texture_page];
   252     while( idx != EMPTY_ENTRY ) {
   253 	texcache_entry_t entry = &texcache_active_list[idx];
   254 	if( entry->texture_addr == texture_addr &&
   255 	    entry->mode == mode &&
   256 	    entry->width == width &&
   257 	    entry->height == height ) {
   258 	    entry->lru_count = texcache_ref_counter++;
   259 	    glBindTexture( GL_TEXTURE_2D, entry->texture_id );
   260 	    return entry->texture_id;
   261 	}
   262         idx = entry->next;
   263     }
   265     /* Not found - check the free list */
   266     int slot = 0;
   268     if( texcache_free_ptr < MAX_TEXTURES ) {
   269 	slot = texcache_free_list[texcache_free_ptr++];
   270     } else {
   271 	slot = texcache_evict();
   272     }
   274     /* Construct new entry */
   275     texcache_active_list[slot].texture_addr = texture_addr;
   276     texcache_active_list[slot].width = width;
   277     texcache_active_list[slot].height = height;
   278     texcache_active_list[slot].mode = mode;
   279     texcache_active_list[slot].lru_count = texcache_ref_counter++;
   281     /* Add entry to the lookup table */
   282     texcache_active_list[slot].next = texcache_page_lookup[texture_page];
   283     texcache_page_lookup[texture_page] = slot;
   285     /* Construct the GL texture */
   286     GLuint texid = texcache_free_list[texcache_free_ptr++];
   287     glBindTexture( GL_TEXTURE_2D, texid );
   288     texcache_load_texture( texture_addr, width, height, mode );
   290     return texcache_active_list[slot].texture_id;
   291 }
.