Search
lxdream.org :: lxdream/src/pvr2/texcache.c :: diff
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...
file annotate diff log raw
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/pvr2/texcache.c Mon Mar 13 12:39:07 2006 +0000
1.3 @@ -0,0 +1,291 @@
1.4 +/**
1.5 + * $Id: texcache.c,v 1.1 2006-03-13 12:39:07 nkeynes Exp $
1.6 + *
1.7 + * Texture cache. Responsible for maintaining a working set of OpenGL
1.8 + * textures.
1.9 + *
1.10 + *
1.11 + * Copyright (c) 2005 Nathan Keynes.
1.12 + *
1.13 + * This program is free software; you can redistribute it and/or modify
1.14 + * it under the terms of the GNU General Public License as published by
1.15 + * the Free Software Foundation; either version 2 of the License, or
1.16 + * (at your option) any later version.
1.17 + *
1.18 + * This program is distributed in the hope that it will be useful,
1.19 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.20 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.21 + * GNU General Public License for more details.
1.22 + */
1.23 +
1.24 +#include <assert.h>
1.25 +#include "pvr2/pvr2.h"
1.26 +
1.27 +/** Specifies the maximum number of OpenGL
1.28 + * textures we're willing to have open at a time. If more are
1.29 + * needed, textures will be evicted in LRU order.
1.30 + */
1.31 +#define MAX_TEXTURES 64
1.32 +
1.33 +/**
1.34 + * Data structure:
1.35 + *
1.36 + * Main operations:
1.37 + * find entry by texture_addr
1.38 + * add new entry
1.39 + * move entry to tail of lru list
1.40 + * remove entry
1.41 + */
1.42 +
1.43 +typedef signed short texcache_entry_index;
1.44 +#define EMPTY_ENTRY -1
1.45 +
1.46 +static texcache_entry_index texcache_free_ptr;
1.47 +static GLuint texcache_free_list[MAX_TEXTURES];
1.48 +
1.49 +typedef struct texcache_entry {
1.50 + uint32_t texture_addr;
1.51 + int width, height, mode;
1.52 + GLuint texture_id;
1.53 + texcache_entry_index next;
1.54 + uint32_t lru_count;
1.55 +} *texcache_entry_t;
1.56 +
1.57 +static uint8_t texcache_page_lookup[PVR2_RAM_PAGES];
1.58 +static uint32_t texcache_active_ptr;
1.59 +static uint32_t texcache_ref_counter;
1.60 +static struct texcache_entry texcache_active_list[MAX_TEXTURES];
1.61 +
1.62 +/**
1.63 + * Initialize the texture cache. Note that the GL context must have been
1.64 + * initialized before calling this function.
1.65 + */
1.66 +void texcache_init( )
1.67 +{
1.68 + int i;
1.69 + GLuint texids[MAX_TEXTURES];
1.70 + glGenTextures( MAX_TEXTURES, texids );
1.71 + for( i=0; i<PVR2_RAM_PAGES; i++ ) {
1.72 + texcache_page_lookup[i] = EMPTY_ENTRY;
1.73 + }
1.74 + for( i=0; i<MAX_TEXTURES; i++ ) {
1.75 + texcache_active_list[i].texture_id = texids[i];
1.76 + texcache_free_list[i] = i;
1.77 + }
1.78 + texcache_free_ptr = 0;
1.79 + texcache_ref_counter = 0;
1.80 +}
1.81 +
1.82 +/**
1.83 + * Flush all textures from the cache, returning them to the free list.
1.84 + */
1.85 +void texcache_flush( )
1.86 +{
1.87 + int i;
1.88 + /* clear structures */
1.89 + for( i=0; i<PVR2_RAM_PAGES; i++ ) {
1.90 + texcache_page_lookup[i] = EMPTY_ENTRY;
1.91 + }
1.92 + for( i=0; i<MAX_TEXTURES; i++ ) {
1.93 + texcache_free_list[i] = i;
1.94 + }
1.95 + texcache_free_ptr = 0;
1.96 + texcache_ref_counter = 0;
1.97 +}
1.98 +
1.99 +/**
1.100 + * Flush all textures and delete. The cache will be non-functional until
1.101 + * the next call to texcache_init(). This would typically be done if
1.102 + * switching GL targets.
1.103 + */
1.104 +void texcache_shutdown( )
1.105 +{
1.106 + GLuint texids[MAX_TEXTURES];
1.107 + int i;
1.108 + texcache_flush();
1.109 +
1.110 + for( i=0; i<MAX_TEXTURES; i++ ) {
1.111 + texids[i] = texcache_active_list[i].texture_id;
1.112 + }
1.113 + glDeleteTextures( MAX_TEXTURES, texids );
1.114 +}
1.115 +
1.116 +/**
1.117 + * Evict all textures contained in the page identified by a texture address.
1.118 + */
1.119 +void texcache_invalidate_page( uint32_t texture_addr ) {
1.120 + uint32_t texture_page = texture_addr >> 12;
1.121 + texcache_entry_index idx = texcache_page_lookup[texture_page];
1.122 + if( idx == EMPTY_ENTRY )
1.123 + return;
1.124 + assert( texcache_free_ptr > 0 );
1.125 + do {
1.126 + texcache_entry_t entry = &texcache_active_list[idx];
1.127 + /* release entry */
1.128 + texcache_free_ptr--;
1.129 + texcache_free_list[texcache_free_ptr] = idx;
1.130 + idx = entry->next;
1.131 + entry->next = EMPTY_ENTRY;
1.132 + } while( idx != EMPTY_ENTRY );
1.133 + texcache_page_lookup[texture_page] = EMPTY_ENTRY;
1.134 +}
1.135 +
1.136 +/**
1.137 + * Evict a single texture from the cache.
1.138 + * @return the slot of the evicted texture.
1.139 + */
1.140 +static texcache_entry_index texcache_evict( void )
1.141 +{
1.142 + /* Full table scan - take over the entry with the lowest lru value */
1.143 + texcache_entry_index slot = 0;
1.144 + int lru_value = texcache_active_list[0].lru_count;
1.145 + int i;
1.146 + for( i=1; i<MAX_TEXTURES; i++ ) {
1.147 + /* FIXME: account for rollover */
1.148 + if( texcache_active_list[i].lru_count < lru_value ) {
1.149 + slot = i;
1.150 + lru_value = texcache_active_list[i].lru_count;
1.151 + }
1.152 + }
1.153 +
1.154 + /* Remove the selected slot from the lookup table */
1.155 + uint32_t evict_page = texcache_active_list[slot].texture_addr;
1.156 + texcache_entry_index replace_next = texcache_active_list[slot].next;
1.157 + texcache_active_list[slot].next = EMPTY_ENTRY; /* Just for safety */
1.158 + if( texcache_page_lookup[evict_page] == slot ) {
1.159 + texcache_page_lookup[evict_page] = replace_next;
1.160 + } else {
1.161 + texcache_entry_index idx = texcache_page_lookup[evict_page];
1.162 + texcache_entry_index next;
1.163 + do {
1.164 + next = texcache_active_list[idx].next;
1.165 + if( next == slot ) {
1.166 + texcache_active_list[idx].next = replace_next;
1.167 + break;
1.168 + }
1.169 + idx = next;
1.170 + } while( next != EMPTY_ENTRY );
1.171 + }
1.172 + return slot;
1.173 +}
1.174 +
1.175 +/**
1.176 + * Load texture data from the given address and parameters into the currently
1.177 + * bound OpenGL texture.
1.178 + */
1.179 +static texcache_load_texture( uint32_t texture_addr, int width, int height,
1.180 + int mode ) {
1.181 + uint32_t bytes = width * height;
1.182 + int bpp = 2;
1.183 + GLint intFormat, format, type;
1.184 + switch( mode & PVR2_TEX_FORMAT_MASK ) {
1.185 + case PVR2_TEX_FORMAT_ARGB1555:
1.186 + bytes <<= 1;
1.187 + intFormat = GL_RGB5_A1;
1.188 + format = GL_RGBA;
1.189 + type = GL_UNSIGNED_SHORT_5_5_5_1;
1.190 + break;
1.191 + case PVR2_TEX_FORMAT_RGB565:
1.192 + bytes <<= 1;
1.193 + intFormat = GL_RGBA;
1.194 + format = GL_RGBA;
1.195 + type = GL_UNSIGNED_SHORT_5_6_5;
1.196 + break;
1.197 + case PVR2_TEX_FORMAT_ARGB4444:
1.198 + bytes <<= 1;
1.199 + intFormat = GL_RGBA4;
1.200 + format = GL_RGBA;
1.201 + type = GL_UNSIGNED_SHORT_4_4_4_4;
1.202 + break;
1.203 + case PVR2_TEX_FORMAT_YUV422:
1.204 + ERROR( "YUV textures not supported" );
1.205 + break;
1.206 + case PVR2_TEX_FORMAT_BUMPMAP:
1.207 + ERROR( "Bumpmap not supported" );
1.208 + break;
1.209 + case PVR2_TEX_FORMAT_IDX4:
1.210 + /* Supported? */
1.211 + bytes >>= 1;
1.212 + intFormat = GL_INTENSITY4;
1.213 + format = GL_COLOR_INDEX;
1.214 + type = GL_UNSIGNED_BYTE;
1.215 + bpp = 0;
1.216 + break;
1.217 + case PVR2_TEX_FORMAT_IDX8:
1.218 + intFormat = GL_INTENSITY8;
1.219 + format = GL_COLOR_INDEX;
1.220 + type = GL_UNSIGNED_BYTE;
1.221 + bpp = 1;
1.222 + break;
1.223 + }
1.224 +
1.225 + unsigned char data[bytes];
1.226 + /* load data from image, detwiddling/uncompressing as required */
1.227 + if( PVR2_TEX_IS_COMPRESSED(mode) ) {
1.228 + ERROR( "VQ Compression not supported" );
1.229 + } else {
1.230 + pvr2_vram64_read( &data, texture_addr, bytes );
1.231 + if( PVR2_TEX_IS_TWIDDLED(mode) ) {
1.232 + /* Untwiddle */
1.233 + }
1.234 + }
1.235 + /* Pass to GL */
1.236 + glTexImage2D( GL_TEXTURE_2D, 0, intFormat, width, height, 0, format, type,
1.237 + data );
1.238 +}
1.239 +
1.240 +/**
1.241 + * Return a texture ID for the texture specified at the supplied address
1.242 + * and given parameters (the same sequence of bytes could in theory have
1.243 + * multiple interpretations). We use the texture address as the primary
1.244 + * index, but allow for multiple instances at each address. The texture
1.245 + * will be bound to the GL_TEXTURE_2D target before being returned.
1.246 + *
1.247 + * If the texture has already been bound, return the ID to which it was
1.248 + * bound. Otherwise obtain an unused texture ID and set it up appropriately.
1.249 + */
1.250 +GLuint texcache_get_texture( uint32_t texture_addr, int width, int height,
1.251 + int mode )
1.252 +{
1.253 + uint32_t texture_page = texture_addr >> 12;
1.254 + texcache_entry_index idx = texcache_page_lookup[texture_page];
1.255 + while( idx != EMPTY_ENTRY ) {
1.256 + texcache_entry_t entry = &texcache_active_list[idx];
1.257 + if( entry->texture_addr == texture_addr &&
1.258 + entry->mode == mode &&
1.259 + entry->width == width &&
1.260 + entry->height == height ) {
1.261 + entry->lru_count = texcache_ref_counter++;
1.262 + glBindTexture( GL_TEXTURE_2D, entry->texture_id );
1.263 + return entry->texture_id;
1.264 + }
1.265 + idx = entry->next;
1.266 + }
1.267 +
1.268 + /* Not found - check the free list */
1.269 + int slot = 0;
1.270 +
1.271 + if( texcache_free_ptr < MAX_TEXTURES ) {
1.272 + slot = texcache_free_list[texcache_free_ptr++];
1.273 + } else {
1.274 + slot = texcache_evict();
1.275 + }
1.276 +
1.277 + /* Construct new entry */
1.278 + texcache_active_list[slot].texture_addr = texture_addr;
1.279 + texcache_active_list[slot].width = width;
1.280 + texcache_active_list[slot].height = height;
1.281 + texcache_active_list[slot].mode = mode;
1.282 + texcache_active_list[slot].lru_count = texcache_ref_counter++;
1.283 +
1.284 + /* Add entry to the lookup table */
1.285 + texcache_active_list[slot].next = texcache_page_lookup[texture_page];
1.286 + texcache_page_lookup[texture_page] = slot;
1.287 +
1.288 + /* Construct the GL texture */
1.289 + GLuint texid = texcache_free_list[texcache_free_ptr++];
1.290 + glBindTexture( GL_TEXTURE_2D, texid );
1.291 + texcache_load_texture( texture_addr, width, height, mode );
1.292 +
1.293 + return texcache_active_list[slot].texture_id;
1.294 +}
.