Search
lxdream.org :: lxdream :: r1140:7dc1c71ece76
lxdream 0.9.1
released Jun 29
Download Now
changeset1140:7dc1c71ece76
parent1139:9af81878480b
child1141:dc60a0987db9
authornkeynes
dateTue Oct 26 08:39:02 2010 +1000 (9 years ago)
Implement fragment shader to support palette textures 'directly', and
therefore avoid having to reload all palette textures whenever the palette
changes.
src/pvr2/gl_sl.c
src/pvr2/glrender.c
src/pvr2/glutil.c
src/pvr2/glutil.h
src/pvr2/scene.c
src/pvr2/scene.h
src/pvr2/shaders.glsl
src/pvr2/texcache.c
1.1 --- a/src/pvr2/gl_sl.c Sun Oct 24 15:22:59 2010 +1000
1.2 +++ b/src/pvr2/gl_sl.c Tue Oct 26 08:39:02 2010 +1000
1.3 @@ -152,6 +152,16 @@
1.4 glDeleteObjectARB(program);
1.5 }
1.6
1.7 +static inline GLint glsl_get_uniform_location_prim(gl_program_t program, const char *name)
1.8 +{
1.9 + return glGetUniformLocationARB(program, name);
1.10 +}
1.11 +
1.12 +static inline void glsl_set_uniform_int_prim(GLint location, GLint value)
1.13 +{
1.14 + glUniform1iARB(location,value);
1.15 +}
1.16 +
1.17 #elif HAVE_OPENGL_SHADER
1.18
1.19 gboolean glsl_is_supported()
1.20 @@ -260,6 +270,15 @@
1.21 glDeleteProgram(program);
1.22 }
1.23
1.24 +static inline GLint glsl_get_uniform_location_prim(gl_program_t program, const char *name)
1.25 +{
1.26 + return glGetUniformLocation(program, name);
1.27 +}
1.28 +static inline void glsl_set_uniform_int_prim(GLint location, GLint value)
1.29 +{
1.30 + glUniform1i(location, value);
1.31 +}
1.32 +
1.33 #else
1.34 gboolean glsl_is_supported()
1.35 {
1.36 @@ -297,6 +316,15 @@
1.37 void glsl_destroy_program(gl_program_t program)
1.38 {
1.39 }
1.40 +
1.41 +static inline GLint glsl_get_uniform_location_prim(gl_program_t program, const char *name)
1.42 +{
1.43 + return 0;
1.44 +}
1.45 +
1.46 +static inline void glsl_set_uniform_int_prim(GLint location, GLint value)
1.47 +{
1.48 +}
1.49 #endif
1.50
1.51 /****************************************************************************/
1.52 @@ -394,6 +422,20 @@
1.53 }
1.54 }
1.55
1.56 +GLint glsl_get_uniform_location( unsigned program, const char *name )
1.57 +{
1.58 + assert( program >= 0 && program <= GLSL_LAST_PROGRAM );
1.59 +
1.60 + return glsl_get_uniform_location_prim(program_array[program], name);
1.61 +}
1.62 +
1.63 +void glsl_set_uniform_int( unsigned program, const char *name, GLint value )
1.64 +{
1.65 + assert( program >= 0 && program <= GLSL_LAST_PROGRAM );
1.66 + GLint location = glsl_get_uniform_location_prim(program_array[program], name);
1.67 + glsl_set_uniform_int_prim(location, value);
1.68 +}
1.69 +
1.70 void glsl_clear_shader()
1.71 {
1.72 glsl_use_program(0);
2.1 --- a/src/pvr2/glrender.c Sun Oct 24 15:22:59 2010 +1000
2.2 +++ b/src/pvr2/glrender.c Tue Oct 26 08:39:02 2010 +1000
2.3 @@ -44,6 +44,8 @@
2.4 GL_MODULATE
2.5 };
2.6
2.7 +static gboolean have_shaders = FALSE;
2.8 +
2.9 /**
2.10 * Clip the tile bounds to the clipping plane.
2.11 * @return TRUE if the tile was not clipped completely.
2.12 @@ -83,16 +85,17 @@
2.13 }
2.14
2.15
2.16 -
2.17 /**
2.18 * Once-off call to setup the OpenGL context.
2.19 */
2.20 void pvr2_setup_gl_context()
2.21 {
2.22
2.23 - if( glsl_is_supported() ) {
2.24 + if( glsl_is_supported() && isGLMultitextureSupported() ) {
2.25 if( !glsl_load_shaders( ) ) {
2.26 WARN( "Unable to load GL shaders" );
2.27 + } else {
2.28 + have_shaders = TRUE;
2.29 }
2.30 }
2.31
2.32 @@ -125,6 +128,13 @@
2.33 glFogi(GL_FOG_MODE, GL_LINEAR);
2.34 glFogf(GL_FOG_START, 0.0);
2.35 glFogf(GL_FOG_END, 1.0);
2.36 +
2.37 + if( have_shaders ) {
2.38 + glsl_set_shader(DEFAULT_PROGRAM);
2.39 + glsl_set_uniform_int(DEFAULT_PROGRAM, "primary_texture", 0);
2.40 + glsl_set_uniform_int(DEFAULT_PROGRAM, "palette_texture", 1);
2.41 + glsl_clear_shader();
2.42 + }
2.43 }
2.44
2.45 /**
2.46 @@ -146,11 +156,13 @@
2.47 void render_set_tsp_context( uint32_t poly1, uint32_t poly2 )
2.48 {
2.49 glShadeModel( POLY1_SHADE_MODEL(poly1) );
2.50 - if( POLY1_TEXTURED(poly1) ) {
2.51 +
2.52 + if( POLY1_TEXTURED(poly1) && !have_shaders ) {
2.53 if( POLY2_TEX_BLEND(poly2) == 2 )
2.54 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
2.55 else
2.56 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
2.57 +
2.58 }
2.59
2.60 switch( POLY2_FOG_MODE(poly2) ) {
2.61 @@ -482,7 +494,7 @@
2.62 /* Setup vertex array pointers */
2.63 glVertexPointer(3, GL_FLOAT, sizeof(struct vertex_struct), &pvr2_scene.vertex_array[0].x);
2.64 glColorPointer(4, GL_FLOAT, sizeof(struct vertex_struct), &pvr2_scene.vertex_array[0].rgba[0]);
2.65 - glTexCoordPointer(2, GL_FLOAT, sizeof(struct vertex_struct), &pvr2_scene.vertex_array[0].u);
2.66 + glTexCoordPointer(4, GL_FLOAT, sizeof(struct vertex_struct), &pvr2_scene.vertex_array[0].u);
2.67 glSecondaryColorPointerEXT(3, GL_FLOAT, sizeof(struct vertex_struct), pvr2_scene.vertex_array[0].offset_rgba );
2.68 glFogCoordPointerEXT(GL_FLOAT, sizeof(struct vertex_struct), &pvr2_scene.vertex_array[0].offset_rgba[3] );
2.69 /* Turn on the shaders (if available) */
3.1 --- a/src/pvr2/glutil.c Sun Oct 24 15:22:59 2010 +1000
3.2 +++ b/src/pvr2/glutil.c Tue Oct 26 08:39:02 2010 +1000
3.3 @@ -41,6 +41,18 @@
3.4 return isGLExtensionSupported("GL_ARB_texture_mirrored_repeat");
3.5 }
3.6
3.7 +/**
3.8 + * Check if there's at least 2 texture units
3.9 + */
3.10 +gboolean isGLMultitextureSupported()
3.11 +{
3.12 + if( !isGLExtensionSupported("GL_ARB_multitexture") )
3.13 + return FALSE;
3.14 + int units = 0;
3.15 + glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &units);
3.16 + return units >= 2;
3.17 +}
3.18 +
3.19 gboolean isGLVertexRangeSupported()
3.20 {
3.21 return isGLExtensionSupported("GL_APPLE_vertex_array_range") ||
4.1 --- a/src/pvr2/glutil.h Sun Oct 24 15:22:59 2010 +1000
4.2 +++ b/src/pvr2/glutil.h Tue Oct 26 08:39:02 2010 +1000
4.3 @@ -47,6 +47,7 @@
4.4 gboolean isGLVertexBufferSupported();
4.5 gboolean isGLVertexRangeSupported();
4.6 gboolean isGLPixelBufferSupported();
4.7 +gboolean isGLMultitextureSupported();
4.8 gboolean isGLMirroredTextureSupported();
4.9
4.10 /****** Shader handling (gl_sl.c) *****/
4.11 @@ -56,6 +57,8 @@
4.12 void glsl_unload_shaders(void);
4.13 gboolean glsl_set_shader( unsigned program_id );
4.14 void glsl_clear_shader();
4.15 +GLint glsl_get_uniform_location( unsigned program, const char *name );
4.16 +void glsl_set_uniform_int( unsigned program, const char *name, GLint value );
4.17
4.18 /* Convenience formatting function for driver use */
4.19 void fprint_extensions( FILE *out, const char *extensions );
5.1 --- a/src/pvr2/scene.c Sun Oct 24 15:22:59 2010 +1000
5.2 +++ b/src/pvr2/scene.c Tue Oct 26 08:39:02 2010 +1000
5.3 @@ -226,6 +226,18 @@
5.4 return poly;
5.5 }
5.6
5.7 +static float scene_get_palette_offset( uint32_t tex )
5.8 +{
5.9 + uint32_t fmt = (tex & PVR2_TEX_FORMAT_MASK);
5.10 + if( fmt == PVR2_TEX_FORMAT_IDX4 ) {
5.11 + return ((float)((tex & 0x07E00000) >> 17))/1024.0 + 0.0002;
5.12 + } else if( fmt == PVR2_TEX_FORMAT_IDX8 ) {
5.13 + return ((float)((tex & 0x06000000) >> 17))/1024.0 + 0.0002;
5.14 + } else {
5.15 + return -1.0;
5.16 + }
5.17 +}
5.18 +
5.19 /**
5.20 * Decode a single PVR2 renderable vertex (opaque/trans/punch-out, but not shadow
5.21 * volume)
5.22 @@ -237,7 +249,7 @@
5.23 * the normal vertex, half the vertex length for the modified vertex.
5.24 */
5.25 static void pvr2_decode_render_vertex( struct vertex_struct *vert, uint32_t poly1,
5.26 - uint32_t poly2, uint32_t *pvr2_data,
5.27 + uint32_t poly2, uint32_t tex, uint32_t *pvr2_data,
5.28 int modify_offset )
5.29 {
5.30 gboolean force_alpha = !POLY2_ALPHA_ENABLE(poly2);
5.31 @@ -279,16 +291,25 @@
5.32 switch( POLY2_TEX_BLEND(poly2) ) {
5.33 case 0:/* Convert replace => modulate by setting colour values to 1.0 */
5.34 vert->rgba[0] = vert->rgba[1] = vert->rgba[2] = vert->rgba[3] = 1.0;
5.35 + vert->tex_mode = 0.0;
5.36 data.ival++; /* Skip the colour word */
5.37 break;
5.38 + case 2: /* Decal */
5.39 + vert->tex_mode = 1.0;
5.40 + unpack_bgra(*data.ival++, vert->rgba);
5.41 + break;
5.42 case 1:
5.43 force_alpha = TRUE;
5.44 /* fall-through */
5.45 - default: /* Can't handle decal this way */
5.46 + default:
5.47 + vert->tex_mode = 0.0;
5.48 unpack_bgra(*data.ival++, vert->rgba);
5.49 break;
5.50 }
5.51 + vert->r = scene_get_palette_offset(tex);
5.52 } else {
5.53 + vert->tex_mode = 2.0;
5.54 + vert->r = -1.0;
5.55 unpack_bgra(*data.ival++, vert->rgba);
5.56 }
5.57
5.58 @@ -357,6 +378,8 @@
5.59 result[i].z = rz;
5.60 result[i].u = input[1].u + (t*tu) + (s*su);
5.61 result[i].v = input[1].v + (t*tv) + (s*sv);
5.62 + result[i].r = input[1].r; /* Last two components are flat */
5.63 + result[i].tex_mode = input[1].tex_mode;
5.64
5.65 if( is_solid_shaded ) {
5.66 memcpy( result->rgba, input[2].rgba, sizeof(result->rgba) );
5.67 @@ -503,6 +526,8 @@
5.68 dest->z = src->z;
5.69 dest->u = src->u;
5.70 dest->v = src->v;
5.71 + dest->r = src->r;
5.72 + dest->tex_mode = src->tex_mode;
5.73 dest->rgba[0] = src->rgba[0] * scene_shadow_intensity;
5.74 dest->rgba[1] = src->rgba[1] * scene_shadow_intensity;
5.75 dest->rgba[2] = src->rgba[2] * scene_shadow_intensity;
5.76 @@ -531,7 +556,7 @@
5.77 assert( poly != NULL );
5.78 assert( pvr2_scene.vertex_index + poly->vertex_count <= pvr2_scene.vertex_count );
5.79 for( i=0; i<poly->vertex_count; i++ ) {
5.80 - pvr2_decode_render_vertex( &pvr2_scene.vertex_array[pvr2_scene.vertex_index++], context[0], context[1], ptr, 0 );
5.81 + pvr2_decode_render_vertex( &pvr2_scene.vertex_array[pvr2_scene.vertex_index++], context[0], context[1], context[2], ptr, 0 );
5.82 ptr += vertex_length;
5.83 }
5.84 if( is_modified ) {
5.85 @@ -541,7 +566,7 @@
5.86 int mod_offset = (vertex_length - 3)>>1;
5.87 ptr = &pvr2_scene.pvr2_pbuf[poly_idx] + 5;
5.88 for( i=0; i<poly->vertex_count; i++ ) {
5.89 - pvr2_decode_render_vertex( &pvr2_scene.vertex_array[pvr2_scene.vertex_index++], context[0], context[3], ptr, mod_offset );
5.90 + pvr2_decode_render_vertex( &pvr2_scene.vertex_array[pvr2_scene.vertex_index++], context[0], context[3], context[4], ptr, mod_offset );
5.91 ptr += vertex_length;
5.92 }
5.93 } else {
5.94 @@ -572,7 +597,7 @@
5.95 ptr += (is_modified == SHADOW_FULL ? 5 : 3 );
5.96 poly->vertex_index = pvr2_scene.vertex_index;
5.97 for( i=0; i<4; i++ ) {
5.98 - pvr2_decode_render_vertex( &quad[i], context[0], context[1], ptr, 0 );
5.99 + pvr2_decode_render_vertex( &quad[i], context[0], context[1], context[2], ptr, 0 );
5.100 ptr += vertex_length;
5.101 }
5.102 scene_compute_vertexes( &quad[3], 1, &quad[0], !POLY1_GOURAUD_SHADED(context[0]) );
5.103 @@ -589,7 +614,7 @@
5.104 int mod_offset = (vertex_length - 3)>>1;
5.105 ptr = &pvr2_scene.pvr2_pbuf[poly_idx] + 5;
5.106 for( i=0; i<4; i++ ) {
5.107 - pvr2_decode_render_vertex( &quad[4], context[0], context[3], ptr, mod_offset );
5.108 + pvr2_decode_render_vertex( &quad[4], context[0], context[3], context[4], ptr, mod_offset );
5.109 ptr += vertex_length;
5.110 }
5.111 scene_compute_vertexes( &quad[3], 1, &quad[0], !POLY1_GOURAUD_SHADED(context[0]) );
5.112 @@ -759,7 +784,7 @@
5.113 struct vertex_struct base_vertexes[3];
5.114 uint32_t *ptr = context + context_length;
5.115 for( i=0; i<3; i++ ) {
5.116 - pvr2_decode_render_vertex( &base_vertexes[i], context[0], context[1],
5.117 + pvr2_decode_render_vertex( &base_vertexes[i], context[0], context[1], context[2],
5.118 ptr, 0 );
5.119 ptr += vertex_length;
5.120 }
5.121 @@ -774,7 +799,7 @@
5.122 int mod_offset = (vertex_length - 3)>>1;
5.123 ptr = context + context_length;
5.124 for( i=0; i<3; i++ ) {
5.125 - pvr2_decode_render_vertex( &base_vertexes[i], context[0], context[3],
5.126 + pvr2_decode_render_vertex( &base_vertexes[i], context[0], context[3], context[4],
5.127 ptr, mod_offset );
5.128 ptr += vertex_length;
5.129 }
6.1 --- a/src/pvr2/scene.h Sun Oct 24 15:22:59 2010 +1000
6.2 +++ b/src/pvr2/scene.h Tue Oct 26 08:39:02 2010 +1000
6.3 @@ -35,7 +35,7 @@
6.4
6.5
6.6 struct vertex_struct {
6.7 - float u,v;
6.8 + float u,v,r,tex_mode; /* tex-coord quad */
6.9 float x,y,z;
6.10 float rgba[4];
6.11 float offset_rgba[4];
7.1 --- a/src/pvr2/shaders.glsl Sun Oct 24 15:22:59 2010 +1000
7.2 +++ b/src/pvr2/shaders.glsl Tue Oct 26 08:39:02 2010 +1000
7.3 @@ -19,6 +19,52 @@
7.4 * GNU General Public License for more details.
7.5 */
7.6
7.7 +/**
7.8 + * Quick reference for predefined variables
7.9 +
7.10 + * Vertex shader input variables:
7.11 + * vec4 gl_Color;
7.12 + * vec4 gl_SecondaryColor;
7.13 + * vec3 gl_Normal;
7.14 + * vec4 gl_Vertex;
7.15 + * vec4 gl_MultiTexCoord0;
7.16 + * vec4 gl_MultiTexCoord1;
7.17 + * vec4 gl_MultiTexCoord2;
7.18 + * vec4 gl_MultiTexCoord3;
7.19 + * vec4 gl_MultiTexCoord4;
7.20 + * vec4 gl_MultiTexCoord5;
7.21 + * vec4 gl_MultiTexCoord6;
7.22 + * vec4 gl_MultiTexCoord7;
7.23 + * float gl_FogCoord;
7.24 + *
7.25 + * Vertex shader output variables:
7.26 + * vec4 gl_Position; // must be written to
7.27 + * float gl_PointSize; // may be written to
7.28 + * vec4 gl_ClipVertex; // may be written to
7.29 + * varying vec4 gl_FrontColor;
7.30 + * varying vec4 gl_BackColor;
7.31 + * varying vec4 gl_FrontSecondaryColor;
7.32 + * varying vec4 gl_BackSecondaryColor;
7.33 + * varying vec4 gl_TexCoord[]; // at most will be gl_MaxTextureCoords
7.34 + * varying float gl_FogFragCoord;
7.35 + *
7.36 + * Fragment shader input variables:
7.37 + * varying vec4 gl_Color;
7.38 + * varying vec4 gl_SecondaryColor;
7.39 + * varying vec4 gl_TexCoord[]; // at most will be gl_MaxTextureCoords
7.40 + * varying float gl_FogFragCoord;
7.41 + * varying vec2 gl_PointCoord;
7.42 + *
7.43 + * Fragme shader output variables:
7.44 + * vec4 gl_FragCoord;
7.45 + * bool gl_FrontFacing;
7.46 + * vec4 gl_FragColor;
7.47 + * vec4 gl_FragData[gl_MaxDrawBuffers];
7.48 + * float gl_FragDepth;
7.49 +
7.50 + */
7.51 +
7.52 +
7.53 #vertex DEFAULT_VERTEX_SHADER
7.54 void main()
7.55 {
7.56 @@ -32,11 +78,32 @@
7.57 }
7.58
7.59 #fragment DEFAULT_FRAGMENT_SHADER
7.60 +
7.61 +uniform sampler2D primary_texture;
7.62 +uniform sampler1D palette_texture;
7.63 +
7.64 void main()
7.65 {
7.66 - gl_FragColor = gl_Color;
7.67 + vec4 tex = texture2D( primary_texture, gl_TexCoord[0].xy );
7.68 + if( gl_TexCoord[0].z >= 0.0 ) {
7.69 + tex = texture1D( palette_texture, gl_TexCoord[0].z + (tex.a*0.249023) );
7.70 + }
7.71 + /* HACK: unfortunately we have to maintain compatibility with GLSL 1.20,
7.72 + * which only supports varying float. So since we're propagating texcoord
7.73 + * anyway, overload the last component to indicate texture mode.
7.74 + */
7.75 + if( gl_TexCoord[0].w == 0.0 ) {
7.76 + gl_FragColor.rgb = mix( gl_Color.rgb * tex.rgb + gl_SecondaryColor.rgb, gl_Fog.color.rgb, gl_FogFragCoord );
7.77 + gl_FragColor.a = gl_Color.a * tex.a;
7.78 + } else if( gl_TexCoord[0].w >= 1.5 ) {
7.79 + gl_FragColor.rgb = mix( gl_Color.rgb, gl_Fog.color.rgb, gl_FogFragCoord );
7.80 + gl_FragColor.a = gl_Color.a;
7.81 + } else {
7.82 + gl_FragColor.rgb = mix( mix(gl_Color.rgb,tex.rgb,tex.a) + gl_SecondaryColor.rgb, gl_Fog.color.rgb, gl_FogFragCoord);
7.83 + gl_FragColor.a = gl_Color.a;
7.84 + }
7.85 gl_FragDepth = gl_FragCoord.z;
7.86 }
7.87
7.88 -#program DEFAULT_PROGRAM = DEFAULT_VERTEX_SHADER
7.89 +#program DEFAULT_PROGRAM = DEFAULT_VERTEX_SHADER DEFAULT_FRAGMENT_SHADER
7.90
8.1 --- a/src/pvr2/texcache.c Sun Oct 24 15:22:59 2010 +1000
8.2 +++ b/src/pvr2/texcache.c Tue Oct 26 08:39:02 2010 +1000
8.3 @@ -22,6 +22,7 @@
8.4 #include <string.h>
8.5 #include "pvr2/pvr2.h"
8.6 #include "pvr2/pvr2mmio.h"
8.7 +#include "pvr2/glutil.h"
8.8
8.9 /** Specifies the maximum number of OpenGL
8.10 * textures we're willing to have open at a time. If more are
8.11 @@ -59,6 +60,9 @@
8.12 static struct texcache_entry texcache_active_list[MAX_TEXTURES];
8.13 static uint32_t texcache_palette_mode;
8.14 static uint32_t texcache_stride_width;
8.15 +static gboolean texcache_have_palette_shader;
8.16 +static gboolean texcache_palette_valid;
8.17 +static GLuint texcache_palette_texid;
8.18
8.19 /**
8.20 * Initialize the texture cache.
8.21 @@ -77,7 +81,7 @@
8.22 }
8.23 texcache_free_ptr = 0;
8.24 texcache_ref_counter = 0;
8.25 - texcache_palette_mode = 0;
8.26 + texcache_palette_mode = -1;
8.27 texcache_stride_width = 0;
8.28 }
8.29
8.30 @@ -90,6 +94,23 @@
8.31 int i;
8.32 GLuint texids[MAX_TEXTURES];
8.33
8.34 + if( glsl_is_supported() && isGLMultitextureSupported ) {
8.35 + texcache_have_palette_shader = TRUE;
8.36 + texcache_palette_valid = FALSE;
8.37 + glGenTextures(1, &texcache_palette_texid );
8.38 +
8.39 + /* Bind the texture and set the params */
8.40 + glActiveTexture(GL_TEXTURE1);
8.41 + glBindTexture(GL_TEXTURE_1D, texcache_palette_texid);
8.42 + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
8.43 + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
8.44 + glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP );
8.45 + glActiveTexture(GL_TEXTURE0);
8.46 +
8.47 + } else {
8.48 + texcache_have_palette_shader = FALSE;
8.49 + }
8.50 +
8.51 glGenTextures( MAX_TEXTURES, texids );
8.52 for( i=0; i<MAX_TEXTURES; i++ ) {
8.53 texcache_active_list[i].texture_id = texids[i];
8.54 @@ -137,6 +158,9 @@
8.55 int i;
8.56 texcache_flush();
8.57
8.58 + if( texcache_have_palette_shader )
8.59 + glDeleteTextures( 1, &texcache_palette_texid );
8.60 +
8.61 for( i=0; i<MAX_TEXTURES; i++ ) {
8.62 texids[i] = texcache_active_list[i].texture_id;
8.63 }
8.64 @@ -220,20 +244,83 @@
8.65 }
8.66
8.67 /**
8.68 - * Mark all textures that use the palette table as needing a re-read (ie
8.69 - * for when the palette is changed. We could track exactly which ones are
8.70 - * affected, but it's not clear that the extra maintanence overhead is
8.71 - * worthwhile.
8.72 + * Load the palette into 4 textures of 256 entries each. This mirrors the
8.73 + * banking done by the PVR2 for 8-bit textures, and also ensures that we
8.74 + * can use 8-bit paletted textures ourselves.
8.75 + */
8.76 +static void texcache_load_palette_texture( gboolean format_changed )
8.77 +{
8.78 + GLint format, type, intFormat = GL_RGBA;
8.79 + unsigned i;
8.80 + int bpp = 2;
8.81 + uint32_t *palette = (uint32_t *)mmio_region_PVR2PAL.mem;
8.82 + uint16_t packed_palette[1024];
8.83 + char *data = (char *)palette;
8.84 +
8.85 + switch( texcache_palette_mode ) {
8.86 + case 0: /* ARGB1555 */
8.87 + format = GL_BGRA;
8.88 + type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
8.89 + break;
8.90 + case 1: /* RGB565 */
8.91 + intFormat = GL_RGB;
8.92 + format = GL_RGB;
8.93 + type = GL_UNSIGNED_SHORT_5_6_5;
8.94 + break;
8.95 + case 2: /* ARGB4444 */
8.96 + format = GL_BGRA;
8.97 + type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
8.98 + break;
8.99 + case 3: /* ARGB8888 */
8.100 + format = GL_BGRA;
8.101 + type = GL_UNSIGNED_BYTE;
8.102 + bpp = 4;
8.103 + break;
8.104 + default:
8.105 + break; /* Can't happen */
8.106 + }
8.107 +
8.108 +
8.109 + if( bpp == 2 ) {
8.110 + for( i=0; i<1024; i++ ) {
8.111 + packed_palette[i] = (uint16_t)palette[i];
8.112 + }
8.113 + data = (char *)packed_palette;
8.114 +
8.115 + }
8.116 +
8.117 + glActiveTexture(GL_TEXTURE1);
8.118 +// glBindTexture(GL_TEXTURE_1D, texcache_palette_texid);
8.119 + if( format_changed )
8.120 + glTexImage1D(GL_TEXTURE_1D, 0, intFormat, 1024, 0, format, type, data );
8.121 + else
8.122 + glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 1024, format, type, data);
8.123 +// glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
8.124 +// glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
8.125 +// glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP );
8.126 + glActiveTexture(GL_TEXTURE0);
8.127 + texcache_palette_valid = TRUE;
8.128 +}
8.129 +
8.130 +
8.131 +/**
8.132 + * Mark the palette as having changed. If we have palette support (via shaders)
8.133 + * we just flag the palette, otherwise we have to invalidate all palette
8.134 + * textures.
8.135 */
8.136 void texcache_invalidate_palette( )
8.137 {
8.138 - int i;
8.139 - for( i=0; i<MAX_TEXTURES; i++ ) {
8.140 - if( texcache_active_list[i].texture_addr != -1 &&
8.141 - PVR2_TEX_IS_PALETTE(texcache_active_list[i].tex_mode) ) {
8.142 - texcache_evict( i );
8.143 - texcache_free_ptr--;
8.144 - texcache_free_list[texcache_free_ptr] = i;
8.145 + if( texcache_have_palette_shader ) {
8.146 + texcache_palette_valid = FALSE;
8.147 + } else {
8.148 + int i;
8.149 + for( i=0; i<MAX_TEXTURES; i++ ) {
8.150 + if( texcache_active_list[i].texture_addr != -1 &&
8.151 + PVR2_TEX_IS_PALETTE(texcache_active_list[i].tex_mode) ) {
8.152 + texcache_evict( i );
8.153 + texcache_free_ptr--;
8.154 + texcache_free_list[texcache_free_ptr] = i;
8.155 + }
8.156 }
8.157 }
8.158 }
8.159 @@ -256,13 +343,19 @@
8.160
8.161 void texcache_begin_scene( uint32_t palette_mode, uint32_t stride )
8.162 {
8.163 - if( palette_mode != texcache_palette_mode )
8.164 + gboolean format_changed = FALSE;
8.165 + if( palette_mode != texcache_palette_mode ) {
8.166 texcache_invalidate_palette();
8.167 + format_changed = TRUE;
8.168 + }
8.169 if( stride != texcache_stride_width )
8.170 texcache_invalidate_stride();
8.171
8.172 texcache_palette_mode = palette_mode;
8.173 texcache_stride_width = stride;
8.174 +
8.175 + if( !texcache_palette_valid && texcache_have_palette_shader )
8.176 + texcache_load_palette_texture(format_changed);
8.177 }
8.178
8.179 static void decode_pal8_to_32( uint32_t *out, uint8_t *in, int inbytes, uint32_t *pal )
8.180 @@ -291,6 +384,17 @@
8.181 }
8.182 }
8.183
8.184 +static void decode_pal4_to_pal8( uint8_t *out, uint8_t *in, int inbytes )
8.185 +{
8.186 + int i;
8.187 + for( i=0; i<inbytes; i++ ) {
8.188 + *out++ = (uint8_t)(*in & 0x0F);
8.189 + *out++ = (uint8_t)(*in >> 4);
8.190 + in++;
8.191 + }
8.192 +}
8.193 +
8.194 +
8.195
8.196 static void decode_pal4_to_16( uint16_t *out, uint8_t *in, int inbytes, uint32_t *pal )
8.197 {
8.198 @@ -395,7 +499,9 @@
8.199 GLint intFormat = GL_RGBA, format, type;
8.200 int tex_format = mode & PVR2_TEX_FORMAT_MASK;
8.201 struct vq_codebook codebook;
8.202 - GLint filter = GL_LINEAR;
8.203 + GLint min_filter = GL_LINEAR;
8.204 + GLint max_filter = GL_LINEAR;
8.205 + GLint mipmapfilter = GL_LINEAR_MIPMAP_LINEAR;
8.206
8.207 glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
8.208
8.209 @@ -403,30 +509,39 @@
8.210 switch( tex_format ) {
8.211 case PVR2_TEX_FORMAT_IDX4:
8.212 case PVR2_TEX_FORMAT_IDX8:
8.213 - /* For indexed-colour modes, we need to lookup the palette control
8.214 - * word to determine the de-indexed texture format.
8.215 - */
8.216 - switch( texcache_palette_mode ) {
8.217 - case 0: /* ARGB1555 */
8.218 - format = GL_BGRA;
8.219 - type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
8.220 - break;
8.221 - case 1: /* RGB565 */
8.222 - intFormat = GL_RGB;
8.223 - format = GL_RGB;
8.224 - type = GL_UNSIGNED_SHORT_5_6_5;
8.225 - break;
8.226 - case 2: /* ARGB4444 */
8.227 - format = GL_BGRA;
8.228 - type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
8.229 - break;
8.230 - case 3: /* ARGB8888 */
8.231 - format = GL_BGRA;
8.232 + if( texcache_have_palette_shader ) {
8.233 + intFormat = GL_ALPHA8;
8.234 + format = GL_ALPHA;
8.235 type = GL_UNSIGNED_BYTE;
8.236 - bpp_shift = 2;
8.237 - break;
8.238 - default:
8.239 - return; /* Can't happen, but it makes gcc stop complaining */
8.240 + bpp_shift = 0;
8.241 + min_filter = max_filter = GL_NEAREST;
8.242 + mipmapfilter = GL_NEAREST_MIPMAP_NEAREST;
8.243 + } else {
8.244 + /* For indexed-colour modes, we need to lookup the palette control
8.245 + * word to determine the de-indexed texture format.
8.246 + */
8.247 + switch( texcache_palette_mode ) {
8.248 + case 0: /* ARGB1555 */
8.249 + format = GL_BGRA;
8.250 + type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
8.251 + break;
8.252 + case 1: /* RGB565 */
8.253 + intFormat = GL_RGB;
8.254 + format = GL_RGB;
8.255 + type = GL_UNSIGNED_SHORT_5_6_5;
8.256 + break;
8.257 + case 2: /* ARGB4444 */
8.258 + format = GL_BGRA;
8.259 + type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
8.260 + break;
8.261 + case 3: /* ARGB8888 */
8.262 + format = GL_BGRA;
8.263 + type = GL_UNSIGNED_BYTE;
8.264 + bpp_shift = 2;
8.265 + break;
8.266 + default:
8.267 + return; /* Can't happen, but it makes gcc stop complaining */
8.268 + }
8.269 }
8.270 break;
8.271
8.272 @@ -469,8 +584,8 @@
8.273 pvr2_vram64_read_stride( data, width<<bpp_shift, texture_addr, texcache_stride_width<<bpp_shift, height );
8.274 }
8.275 glTexImage2D( GL_TEXTURE_2D, 0, intFormat, width, height, 0, format, type, data );
8.276 - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
8.277 - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
8.278 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
8.279 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, max_filter);
8.280 return;
8.281 }
8.282
8.283 @@ -484,7 +599,7 @@
8.284 int level=0, last_level = 0, mip_width = width, mip_height = height, src_bytes, dest_bytes;
8.285 if( PVR2_TEX_IS_MIPMAPPED(mode) ) {
8.286 uint32_t src_offset = 0;
8.287 - filter = GL_LINEAR_MIPMAP_LINEAR;
8.288 + min_filter = mipmapfilter;
8.289 mip_height = height = width;
8.290 while( (1<<last_level) < width ) {
8.291 last_level++;
8.292 @@ -513,26 +628,35 @@
8.293 unsigned char data[dest_bytes];
8.294 /* load data from image, detwiddling/uncompressing as required */
8.295 if( tex_format == PVR2_TEX_FORMAT_IDX8 ) {
8.296 - src_bytes = (mip_width * mip_height);
8.297 - int bank = (mode >> 25) &0x03;
8.298 - uint32_t *palette = ((uint32_t *)mmio_region_PVR2PAL.mem) + (bank<<8);
8.299 - unsigned char tmp[src_bytes];
8.300 - pvr2_vram64_read_twiddled_8( tmp, texture_addr, mip_width, mip_height );
8.301 - if( bpp_shift == 2 ) {
8.302 - decode_pal8_to_32( (uint32_t *)data, tmp, src_bytes, palette );
8.303 + if( texcache_have_palette_shader ) {
8.304 + pvr2_vram64_read_twiddled_8( data, texture_addr, mip_width, mip_height );
8.305 } else {
8.306 - decode_pal8_to_16( (uint16_t *)data, tmp, src_bytes, palette );
8.307 + src_bytes = (mip_width * mip_height);
8.308 + int bank = (mode >> 25) &0x03;
8.309 + uint32_t *palette = ((uint32_t *)mmio_region_PVR2PAL.mem) + (bank<<8);
8.310 + unsigned char tmp[src_bytes];
8.311 + pvr2_vram64_read_twiddled_8( tmp, texture_addr, mip_width, mip_height );
8.312 + if( bpp_shift == 2 ) {
8.313 + decode_pal8_to_32( (uint32_t *)data, tmp, src_bytes, palette );
8.314 + } else {
8.315 + decode_pal8_to_16( (uint16_t *)data, tmp, src_bytes, palette );
8.316 + }
8.317 }
8.318 } else if( tex_format == PVR2_TEX_FORMAT_IDX4 ) {
8.319 src_bytes = (mip_width * mip_height) >> 1;
8.320 - int bank = (mode >>21 ) & 0x3F;
8.321 - uint32_t *palette = ((uint32_t *)mmio_region_PVR2PAL.mem) + (bank<<4);
8.322 unsigned char tmp[src_bytes];
8.323 - pvr2_vram64_read_twiddled_4( tmp, texture_addr, mip_width, mip_height );
8.324 - if( bpp_shift == 2 ) {
8.325 - decode_pal4_to_32( (uint32_t *)data, tmp, src_bytes, palette );
8.326 + if( texcache_have_palette_shader ) {
8.327 + pvr2_vram64_read_twiddled_4( tmp, texture_addr, mip_width, mip_height );
8.328 + decode_pal4_to_pal8( data, tmp, src_bytes );
8.329 } else {
8.330 - decode_pal4_to_16( (uint16_t *)data, tmp, src_bytes, palette );
8.331 + int bank = (mode >>21 ) & 0x3F;
8.332 + uint32_t *palette = ((uint32_t *)mmio_region_PVR2PAL.mem) + (bank<<4);
8.333 + pvr2_vram64_read_twiddled_4( tmp, texture_addr, mip_width, mip_height );
8.334 + if( bpp_shift == 2 ) {
8.335 + decode_pal4_to_32( (uint32_t *)data, tmp, src_bytes, palette );
8.336 + } else {
8.337 + decode_pal4_to_16( (uint16_t *)data, tmp, src_bytes, palette );
8.338 + }
8.339 }
8.340 } else if( tex_format == PVR2_TEX_FORMAT_YUV422 ) {
8.341 src_bytes = ((mip_width*mip_height)<<1);
8.342 @@ -575,8 +699,8 @@
8.343 }
8.344 }
8.345
8.346 - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
8.347 - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
8.348 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
8.349 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, max_filter);
8.350 }
8.351
8.352 static int texcache_find_texture_slot( uint32_t poly2_masked_word, uint32_t texture_word )
8.353 @@ -646,11 +770,15 @@
8.354 GLuint texcache_get_texture( uint32_t poly2_word, uint32_t texture_word )
8.355 {
8.356 poly2_word &= 0x000F803F; /* Get just the texture-relevant bits */
8.357 - int slot = texcache_find_texture_slot( poly2_word, texture_word );
8.358 + uint32_t texture_lookup = texture_word;
8.359 + if( PVR2_TEX_IS_PALETTE(texture_lookup) ) {
8.360 + texture_lookup &= 0xF81FFFFF; /* Mask out the bank bits */
8.361 + }
8.362 + int slot = texcache_find_texture_slot( poly2_word, texture_lookup );
8.363
8.364 if( slot == -1 ) {
8.365 /* Not found - check the free list */
8.366 - slot = texcache_alloc_texture_slot( poly2_word, texture_word );
8.367 + slot = texcache_alloc_texture_slot( poly2_word, texture_lookup );
8.368
8.369 /* Construct the GL texture */
8.370 uint32_t texture_addr = (texture_word & 0x000FFFFF)<<3;
8.371 @@ -750,3 +878,23 @@
8.372 assert( slot_found[i] != 0 );
8.373 }
8.374 }
8.375 +
8.376 +/**
8.377 + * Dump the contents of the texture cache
8.378 + */
8.379 +void texcache_dump()
8.380 +{
8.381 + unsigned i;
8.382 + for( i=0; i< PVR2_RAM_PAGES; i++ ) {
8.383 + int slot = texcache_page_lookup[i];
8.384 + while( slot != EMPTY_ENTRY ) {
8.385 + fprintf( stderr, "%-3d: %08X %dx%d (%08X %08X)\n", slot,
8.386 + texcache_active_list[slot].texture_addr,
8.387 + POLY2_TEX_WIDTH(texcache_active_list[slot].poly2_mode),
8.388 + POLY2_TEX_HEIGHT(texcache_active_list[slot].poly2_mode),
8.389 + texcache_active_list[slot].poly2_mode,
8.390 + texcache_active_list[slot].tex_mode );
8.391 + slot = texcache_active_list[slot].next;
8.392 + }
8.393 + }
8.394 +}
.