Pages: [1]
  Print  
Author Topic: Hardware-specific shaders (PATCH)  (Read 10094 times)
andrewj
Member


Cakes 24
Posts: 584



« on: May 30, 2012, 05:45:46 AM »

The following patch implements hardware-specific shader files.
This patch is against the 0.8.8 open arena engine code.

These are placed in hardware/NAME/scripts (where NAME is "voodoo" or whatever), and get loaded after all the normal shaders, and hence a hardware-specific shader always takes precedence over a normal shader.

I think this should be used for GLSL support too, but that's not my ballpark.

Code:
diff -r -u ./code/renderer/tr_shader.c ./code/renderer/tr_shader.c
--- ./code/renderer/tr_shader.c 2011-12-25 20:06:49.000000000 +1100
+++ ./code/renderer/tr_shader.c 2012-05-30 20:54:17.000000000 +1000
@@ -4264,6 +4264,25 @@
  ri.Printf (PRINT_ALL, "------------------\n");
 }
 
+/* andrewj: added this */
+static char * GetHardwareName( void )
+{
+
+ // TODO: if (GLSL_enabled) return "glsl";
+
+ switch (glConfig.hardwareType)
+ {
+ case GLHW_3DFX_2D3D: return "voodoo";
+ case GLHW_RIVA128:   return "riva128";
+ case GLHW_RAGEPRO:   return "ragepro";
+ case GLHW_PERMEDIA2: return "permedia2";
+
+ // TODO: case GLHW_POWERVR: return "powervr";
+
+  default: return NULL;
+ }
+}
+
 /*
 ====================
 ScanAndLoadShaderFiles
@@ -4273,20 +4292,44 @@
 =====================
 */
 #define MAX_SHADER_FILES 4096
+#define MAX_HW_SHADER_FILES 1024
 static void ScanAndLoadShaderFiles( void )
 {
  char **shaderFiles;
- char *buffers[MAX_SHADER_FILES];
+ char *buffers[MAX_SHADER_FILES + MAX_HW_SHADER_FILES];
  char *p;
  int numShaderFiles;
  int i;
  char *oldp, *token, *hashMem, *textEnd;
+ char *hw_name;
+ char ** hwShaderFiles;
+ int numHWShaderFiles;
  int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash, size;
 
  long sum = 0, summand;
  // scan for shader files
  shaderFiles = ri.FS_ListFiles( "scripts", ".shader", &numShaderFiles );
 
+ // andrewj: add hardware-specific shaders
+ hw_name = GetHardwareName();
+
+ if ( hw_name && hw_name[0] )
+ {
+ char hw_directory[128];
+ Com_sprintf( hw_directory, sizeof( hw_directory ), "hardware/%s/scripts", hw_name );
+
+ hwShaderFiles = ri.FS_ListFiles( hw_directory, ".shader", &numHWShaderFiles );
+
+ if ( numHWShaderFiles > MAX_HW_SHADER_FILES ) {
+ numHWShaderFiles = MAX_HW_SHADER_FILES;
+ }
+ }
+ else
+ {
+ hwShaderFiles = NULL;
+ numHWShaderFiles = 0;
+ }
+
  if ( !shaderFiles || !numShaderFiles )
  {
  ri.Printf( PRINT_WARNING, "WARNING: no shader files found\n" );
@@ -4298,14 +4341,18 @@
  }
 
  // load and parse shader files
- for ( i = 0; i < numShaderFiles; i++ )
+ for ( i = 0; i < numShaderFiles + numHWShaderFiles; i++ )
  {
  char filename[MAX_QPATH];
 
- Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i] );
+ if (i < numHWShaderFiles)
+ Com_sprintf( filename, sizeof( filename ), "hardware/%s/scripts/%s", hw_name, hwShaderFiles[i] );
+ else
+ Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i - numHWShaderFiles] );
+
  ri.Printf( PRINT_DEVELOPER, "...loading '%s'\n", filename );
  summand = ri.FS_ReadFile( filename, (void **)&buffers[i] );
-
+
  if ( !buffers[i] )
  ri.Error( ERR_DROP, "Couldn't load %s", filename );
 
@@ -4338,28 +4385,39 @@
  sum += summand;
  }
 
+ numShaderFiles += numHWShaderFiles;
+
  // build single large buffer
  s_shaderText = ri.Hunk_Alloc( sum + numShaderFiles*2, h_low );
  s_shaderText[ 0 ] = '\0';
  textEnd = s_shaderText;
  
- // free in reverse order, so the temp files are all dumped
- for ( i = numShaderFiles - 1; i >= 0 ; i-- )
+ // andrewj: changed this to append in forward order, which means that individual
+ //          shaders defined in later paks can properly override earlier ones.
+ for ( i = 0 ; i < numShaderFiles ; i++ )
  {
- if ( !buffers[i] )
- continue;
+ if ( buffers[i] )
+ {
+ strcat( textEnd, buffers[i] );
+ strcat( textEnd, "\n" );
 
- strcat( textEnd, buffers[i] );
- strcat( textEnd, "\n" );
- textEnd += strlen( textEnd );
- ri.FS_FreeFile( buffers[i] );
+ textEnd += strlen( textEnd );
+ }
  }
 
+ // free in reverse order, so the temp files are all dumped
+ for ( i = numShaderFiles - 1; i >= 0 ; i-- )
+ if ( buffers[i] )
+ ri.FS_FreeFile( buffers[i] );
+
  COM_Compress( s_shaderText );
 
  // free up memory
  ri.FS_FreeFileList( shaderFiles );
 
+ if ( hwShaderFiles )
+ ri.FS_FreeFileList( hwShaderFiles );
+
  Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));
  size = 0;
 
Logged
Hitchhiker
Member


Cakes 11
Posts: 181


« Reply #1 on: June 04, 2012, 12:31:53 PM »

regarding the glsl, this is a very good solution. I've been taking it easy with my glsl changes since the modular renderers were talked about, mainly for reason of not knowing how they could all work with the same shader files - your code resolves this.
Logged
fromhell
Administrator
GET A LIFE!
**********

Cakes 35
Posts: 14520



WWW
« Reply #2 on: July 26, 2012, 10:37:45 PM »

I didn't want to bitrot my powervr hacking attempts any further, so here's the changed code files for my hacked up methods. Can't make a diff right now.

There's probably even more crap leftover from other unrelated hacks such as a failure to implement tinysdgl, reimplementing tinyfont for the console in low resolution modes, and an attempt to not overbright rgbGen const.

This is all dirty and experimental and probably shouldn't be implemented in its current state. It adds these cvars (which may need to be cheat-protected)


r_mocksw - Mocks what a (theoretical) software renderer or Matrox Mystique could look like
r_mockrage - Mocks what a Rage Pro could look like (incomplete, but basically taking off modulation of any kind for alphas)
r_mockvr - Mocks what PowerVR PCX2 looks like (almost - the different sorting isn't mocked). This is useful for debugging shaders being developed for this card.
r_hackvr - Hacks some functions to enable it to be PowerVR friendly - like flares will start to alpha fade, dynamic light textures get alpha'd


The real guts of the hack is to add an alphahack check in Upload32, determining how to process from the alphahack command in the shader. This would process the texture in various ways like
Code:
// fromhell - the meat of the alpha hack
if (r_mockvr->integer){
if( alphahack == 1 ) // Additives
{

for ( i = 0; i < c; i++ )
{
byte alfa = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]);
scan[i*4 + 3] = alfa;

// stupid normalization hack
/* thecolor[0] = scan[i*4];
thecolor[1] = scan[i*4 + 1];
thecolor[2] = scan[i*4 + 2];
NormalizeColor( thecolor, thecolor);
scan[i*4] = thecolor[0];
scan[i*4 + 1] = thecolor[1];
scan[i*4 + 2] = thecolor[2]; */
}
}

if( alphahack == 3 ) // Subtractives
{
for ( i = 0; i < c; i++ )
{
byte alfa = LUMA(scan[i*4] * -1, scan[i*4 + 1] * -1, scan[i*4 + 2] * -1);
scan[i*4 + 3] = alfa;
}
}
if( alphahack == 4 ) // Multiplies
{
for ( i = 0; i < c; i++ )
{
byte alfa = LUMA(scan[i*4] + 127, scan[i*4 + 1] + 127, scan[i*4 + 2] + 127);
scan[i*4 + 3] = alfa;
}
}

if( alphahack == 2 ) // Demoting alphas (i.e. for shiny walls and some players)
{
for ( i = 0; i < c; i++ )
{
scan[i*4 + 3] = 255;
}
}

if( alphahack == 5 ) // Additives, special for rgbGens
{

for ( i = 0; i < c; i++ )
{
byte alfa = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]);
scan[i*4 + 3] = alfa;
scan[i*4] = 255;
scan[i*4 + 1] = 255;
scan[i*4 + 2] = 255;
}
}

What I really should do is start over using the modular renderer as a base.
Logged

asking when OA3 will be done won't get OA3 done.
Progress of OA3 currently occurs behind closed doors alone

I do not provide technical support either.

new code development on github
Pages: [1]
  Print  
 
Jump to: