2020-11-18 00:21:07 +01:00
/*
2023-01-06 15:36:05 -05:00
* 86 Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus .
2020-11-18 00:21:07 +01:00
*
2023-01-06 15:36:05 -05:00
* This file is part of the 86 Box distribution .
2020-11-18 00:21:07 +01:00
*
2023-01-06 15:36:05 -05:00
* 3 DFX Voodoo emulation .
2020-11-18 00:21:07 +01:00
*
*
*
2023-01-06 15:36:29 -05:00
* Authors : Sarah Walker , < https : //pcem-emulator.co.uk/>
2020-11-18 00:21:07 +01:00
*
2023-01-06 15:36:05 -05:00
* Copyright 2008 - 2020 Sarah Walker .
2020-11-18 00:21:07 +01:00
*/
2022-10-27 11:20:31 -04:00
# include <stdarg.h>
2020-11-18 00:21:07 +01:00
# include <stdio.h>
# include <stdint.h>
# include <string.h>
# include <stdlib.h>
# include <stddef.h>
# include <wchar.h>
# include <math.h>
2022-10-27 11:20:31 -04:00
# define HAVE_STDARG_H
2020-11-18 00:21:07 +01:00
# include <86box/86box.h>
# include "cpu.h"
# include <86box/machine.h>
# include <86box/device.h>
# include <86box/mem.h>
# include <86box/timer.h>
# include <86box/device.h>
# include <86box/plat.h>
2022-04-19 23:06:39 +02:00
# include <86box/thread.h>
2020-11-18 00:21:07 +01:00
# include <86box/video.h>
# include <86box/vid_svga.h>
# include <86box/vid_voodoo_common.h>
# include <86box/vid_voodoo_dither.h>
# include <86box/vid_voodoo_regs.h>
# include <86box/vid_voodoo_render.h>
# include <86box/vid_voodoo_texture.h>
# ifdef ENABLE_VOODOO_TEXTURE_LOG
int voodoo_texture_do_log = ENABLE_VOODOO_TEXTURE_LOG ;
static void
voodoo_texture_log ( const char * fmt , . . . )
{
va_list ap ;
if ( voodoo_texture_do_log ) {
2022-08-31 19:19:29 -04:00
va_start ( ap , fmt ) ;
pclog_ex ( fmt , ap ) ;
va_end ( ap ) ;
2020-11-18 00:21:07 +01:00
}
}
# else
2022-08-31 19:19:29 -04:00
# define voodoo_texture_log(fmt, ...)
2020-11-18 00:21:07 +01:00
# endif
2022-08-31 19:19:29 -04:00
void
2022-11-03 17:46:13 -04:00
voodoo_recalc_tex12 ( voodoo_t * voodoo , int tmu )
{
int aspect = ( voodoo - > params . tLOD [ tmu ] > > 21 ) & 3 ;
2023-06-01 18:32:25 -04:00
int width = 256 ;
int height = 256 ;
2022-11-03 17:46:13 -04:00
int shift = 8 ;
uint32_t base = voodoo - > params . texBaseAddr [ tmu ] ;
uint32_t offset = 0 ;
int tex_lod = 0 ;
if ( voodoo - > params . tLOD [ tmu ] & LOD_S_IS_WIDER )
height > > = aspect ;
else {
width > > = aspect ;
shift - = aspect ;
}
if ( ( voodoo - > params . tLOD [ tmu ] & LOD_SPLIT ) & & ( voodoo - > params . tLOD [ tmu ] & LOD_ODD ) ) {
width > > = 1 ;
height > > = 1 ;
shift - - ;
tex_lod + + ;
if ( voodoo - > params . tLOD [ tmu ] & LOD_TMULTIBASEADDR )
base = voodoo - > params . texBaseAddr1 [ tmu ] ;
}
2023-06-01 18:32:25 -04:00
for ( uint8_t lod = 0 ; lod < = LOD_MAX + 1 ; lod + + ) {
2022-11-03 17:46:13 -04:00
if ( ! width )
width = 1 ;
if ( ! height )
height = 1 ;
if ( shift < 0 )
shift = 0 ;
voodoo - > params . tex_base [ tmu ] [ lod ] = base + offset ;
if ( voodoo - > params . tformat [ tmu ] & 8 )
voodoo - > params . tex_end [ tmu ] [ lod ] = base + offset + ( width * height * 2 ) ;
else
voodoo - > params . tex_end [ tmu ] [ lod ] = base + offset + ( width * height ) ;
voodoo - > params . tex_w_mask [ tmu ] [ lod ] = width - 1 ;
voodoo - > params . tex_w_nmask [ tmu ] [ lod ] = ~ ( width - 1 ) ;
voodoo - > params . tex_h_mask [ tmu ] [ lod ] = height - 1 ;
voodoo - > params . tex_shift [ tmu ] [ lod ] = shift ;
voodoo - > params . tex_lod [ tmu ] [ lod ] = tex_lod ;
if ( ! ( voodoo - > params . tLOD [ tmu ] & LOD_SPLIT ) | | ( ( lod & 1 ) & & ( voodoo - > params . tLOD [ tmu ] & LOD_ODD ) ) | | ( ! ( lod & 1 ) & & ! ( voodoo - > params . tLOD [ tmu ] & LOD_ODD ) ) ) {
if ( ! ( voodoo - > params . tLOD [ tmu ] & LOD_ODD ) | | lod ! = 0 ) {
if ( voodoo - > params . tformat [ tmu ] & 8 )
offset + = width * height * 2 ;
else
offset + = width * height ;
if ( voodoo - > params . tLOD [ tmu ] & LOD_SPLIT ) {
width > > = 2 ;
height > > = 2 ;
shift - = 2 ;
tex_lod + = 2 ;
} else {
width > > = 1 ;
height > > = 1 ;
shift - - ;
tex_lod + + ;
}
if ( voodoo - > params . tLOD [ tmu ] & LOD_TMULTIBASEADDR ) {
switch ( tex_lod ) {
case 0 :
base = voodoo - > params . texBaseAddr [ tmu ] ;
break ;
case 1 :
base = voodoo - > params . texBaseAddr1 [ tmu ] ;
break ;
case 2 :
base = voodoo - > params . texBaseAddr2 [ tmu ] ;
break ;
default :
base = voodoo - > params . texBaseAddr38 [ tmu ] ;
break ;
}
}
}
}
}
voodoo - > params . tex_width [ tmu ] = width ;
}
void
voodoo_recalc_tex3 ( voodoo_t * voodoo , int tmu )
2020-11-18 00:21:07 +01:00
{
2022-08-31 19:19:29 -04:00
int aspect = ( voodoo - > params . tLOD [ tmu ] > > 21 ) & 3 ;
2023-06-01 18:32:25 -04:00
int width = 256 ;
int height = 256 ;
2022-08-31 19:19:29 -04:00
int shift = 8 ;
int lod ;
uint32_t base = voodoo - > params . texBaseAddr [ tmu ] ;
uint32_t offset = 0 ;
int tex_lod = 0 ;
uint32_t offsets [ LOD_MAX + 3 ] ;
2023-06-01 18:32:25 -04:00
int widths [ LOD_MAX + 3 ] ;
int heights [ LOD_MAX + 3 ] ;
int shifts [ LOD_MAX + 3 ] ;
2022-08-31 19:19:29 -04:00
if ( voodoo - > params . tLOD [ tmu ] & LOD_S_IS_WIDER )
height > > = aspect ;
else {
width > > = aspect ;
shift - = aspect ;
}
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
for ( lod = 0 ; lod < = LOD_MAX + 2 ; lod + + ) {
offsets [ lod ] = offset ;
widths [ lod ] = width > > lod ;
heights [ lod ] = height > > lod ;
shifts [ lod ] = shift - lod ;
if ( ! widths [ lod ] )
widths [ lod ] = 1 ;
if ( ! heights [ lod ] )
heights [ lod ] = 1 ;
if ( shifts [ lod ] < 0 )
shifts [ lod ] = 0 ;
if ( ! ( voodoo - > params . tLOD [ tmu ] & LOD_SPLIT ) | | ( ( lod & 1 ) & & ( voodoo - > params . tLOD [ tmu ] & LOD_ODD ) ) | | ( ! ( lod & 1 ) & & ! ( voodoo - > params . tLOD [ tmu ] & LOD_ODD ) ) ) {
if ( voodoo - > params . tformat [ tmu ] & 8 )
offset + = ( width > > lod ) * ( height > > lod ) * 2 ;
else
offset + = ( width > > lod ) * ( height > > lod ) ;
2020-11-18 00:21:07 +01:00
}
2022-08-31 19:19:29 -04:00
}
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
if ( ( voodoo - > params . textureMode [ tmu ] & TEXTUREMODE_TRILINEAR ) & & ( voodoo - > params . tLOD [ tmu ] & LOD_ODD ) )
tex_lod + + ; /*Skip LOD 0*/
2023-07-31 18:57:52 -04:00
#if 0
voodoo_texture_log ( " TMU %i: %08x \n " , tmu , voodoo - > params . textureMode [ tmu ] ) ;
# endif
2022-08-31 19:19:29 -04:00
for ( lod = 0 ; lod < = LOD_MAX + 1 ; lod + + ) {
if ( voodoo - > params . tLOD [ tmu ] & LOD_TMULTIBASEADDR ) {
switch ( tex_lod ) {
case 0 :
base = voodoo - > params . texBaseAddr [ tmu ] ;
break ;
case 1 :
base = voodoo - > params . texBaseAddr1 [ tmu ] ;
break ;
case 2 :
base = voodoo - > params . texBaseAddr2 [ tmu ] ;
break ;
default :
base = voodoo - > params . texBaseAddr38 [ tmu ] ;
break ;
}
}
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
voodoo - > params . tex_base [ tmu ] [ lod ] = base + offsets [ tex_lod ] ;
if ( voodoo - > params . tformat [ tmu ] & 8 )
voodoo - > params . tex_end [ tmu ] [ lod ] = base + offsets [ tex_lod ] + ( widths [ tex_lod ] * heights [ tex_lod ] * 2 ) ;
else
voodoo - > params . tex_end [ tmu ] [ lod ] = base + offsets [ tex_lod ] + ( widths [ tex_lod ] * heights [ tex_lod ] ) ;
voodoo - > params . tex_w_mask [ tmu ] [ lod ] = widths [ tex_lod ] - 1 ;
voodoo - > params . tex_w_nmask [ tmu ] [ lod ] = ~ ( widths [ tex_lod ] - 1 ) ;
voodoo - > params . tex_h_mask [ tmu ] [ lod ] = heights [ tex_lod ] - 1 ;
voodoo - > params . tex_shift [ tmu ] [ lod ] = shifts [ tex_lod ] ;
voodoo - > params . tex_lod [ tmu ] [ lod ] = tex_lod ;
if ( ! ( voodoo - > params . textureMode [ tmu ] & TEXTUREMODE_TRILINEAR ) | | ( ( lod & 1 ) & & ( voodoo - > params . tLOD [ tmu ] & LOD_ODD ) ) | | ( ! ( lod & 1 ) & & ! ( voodoo - > params . tLOD [ tmu ] & LOD_ODD ) ) ) {
if ( ! ( voodoo - > params . tLOD [ tmu ] & LOD_ODD ) | | lod ! = 0 ) {
if ( voodoo - > params . textureMode [ tmu ] & TEXTUREMODE_TRILINEAR )
tex_lod + = 2 ;
2020-11-18 00:21:07 +01:00
else
2022-08-31 19:19:29 -04:00
tex_lod + + ;
}
2020-11-18 00:21:07 +01:00
}
2022-08-31 19:19:29 -04:00
}
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
voodoo - > params . tex_width [ tmu ] = width ;
2020-11-18 00:21:07 +01:00
}
2022-08-31 19:19:29 -04:00
# define makergba(r, g, b, a) ((b) | ((g) << 8) | ((r) << 16) | ((a) << 24))
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
void
voodoo_use_texture ( voodoo_t * voodoo , voodoo_params_t * params , int tmu )
2020-11-18 00:21:07 +01:00
{
2023-06-01 18:32:25 -04:00
int c ;
int lod_min ;
int lod_max ;
uint32_t addr = 0 ;
uint32_t addr_end ;
2022-08-31 19:19:29 -04:00
uint32_t palette_checksum ;
lod_min = ( params - > tLOD [ tmu ] > > 2 ) & 15 ;
lod_max = ( params - > tLOD [ tmu ] > > 8 ) & 15 ;
if ( params - > tformat [ tmu ] = = TEX_PAL8 | | params - > tformat [ tmu ] = = TEX_APAL8 | | params - > tformat [ tmu ] = = TEX_APAL88 ) {
if ( voodoo - > palette_dirty [ tmu ] ) {
palette_checksum = 0 ;
for ( c = 0 ; c < 256 ; c + + )
palette_checksum ^ = voodoo - > palette [ tmu ] [ c ] . u ;
voodoo - > palette_checksum [ tmu ] = palette_checksum ;
voodoo - > palette_dirty [ tmu ] = 0 ;
} else
palette_checksum = voodoo - > palette_checksum [ tmu ] ;
} else
palette_checksum = 0 ;
if ( ( voodoo - > params . tLOD [ tmu ] & LOD_SPLIT ) & & ( voodoo - > params . tLOD [ tmu ] & LOD_ODD ) & & ( voodoo - > params . tLOD [ tmu ] & LOD_TMULTIBASEADDR ) )
addr = params - > texBaseAddr1 [ tmu ] ;
else
addr = params - > texBaseAddr [ tmu ] ;
/*Try to find texture in cache*/
for ( c = 0 ; c < TEX_CACHE_MAX ; c + + ) {
if ( voodoo - > texture_cache [ tmu ] [ c ] . base = = addr & & voodoo - > texture_cache [ tmu ] [ c ] . tLOD = = ( params - > tLOD [ tmu ] & 0xf00fff ) & & voodoo - > texture_cache [ tmu ] [ c ] . palette_checksum = = palette_checksum ) {
params - > tex_entry [ tmu ] = c ;
voodoo - > texture_cache [ tmu ] [ c ] . refcount + + ;
return ;
2020-11-18 00:21:07 +01:00
}
2022-08-31 19:19:29 -04:00
}
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
/*Texture not found, search for unused texture*/
do {
for ( c = 0 ; c < TEX_CACHE_MAX ; c + + ) {
voodoo - > texture_last_removed + + ;
voodoo - > texture_last_removed & = ( TEX_CACHE_MAX - 1 ) ;
if ( voodoo - > texture_cache [ tmu ] [ voodoo - > texture_last_removed ] . refcount = = voodoo - > texture_cache [ tmu ] [ voodoo - > texture_last_removed ] . refcount_r [ 0 ] & & ( voodoo - > render_threads = = 1 | | voodoo - > texture_cache [ tmu ] [ voodoo - > texture_last_removed ] . refcount = = voodoo - > texture_cache [ tmu ] [ voodoo - > texture_last_removed ] . refcount_r [ 1 ] ) )
break ;
2020-11-18 00:21:07 +01:00
}
2022-08-31 19:19:29 -04:00
if ( c = = TEX_CACHE_MAX )
voodoo_wait_for_render_thread_idle ( voodoo ) ;
} while ( c = = TEX_CACHE_MAX ) ;
if ( c = = TEX_CACHE_MAX )
fatal ( " Texture cache full! \n " ) ;
c = voodoo - > texture_last_removed ;
if ( ( voodoo - > params . tLOD [ tmu ] & LOD_SPLIT ) & & ( voodoo - > params . tLOD [ tmu ] & LOD_ODD ) & & ( voodoo - > params . tLOD [ tmu ] & LOD_TMULTIBASEADDR ) )
voodoo - > texture_cache [ tmu ] [ c ] . base = params - > texBaseAddr1 [ tmu ] ;
else
voodoo - > texture_cache [ tmu ] [ c ] . base = params - > texBaseAddr [ tmu ] ;
voodoo - > texture_cache [ tmu ] [ c ] . tLOD = params - > tLOD [ tmu ] & 0xf00fff ;
lod_min = ( params - > tLOD [ tmu ] > > 2 ) & 15 ;
lod_max = ( params - > tLOD [ tmu ] > > 8 ) & 15 ;
2023-07-31 18:57:52 -04:00
#if 0
voodoo_texture_log ( " add new texture to %i tformat=%i %08x LOD=%i-%i tmu=%i \n " , c , voodoo - > params . tformat [ tmu ] , params - > texBaseAddr [ tmu ] , lod_min , lod_max , tmu ) ;
# endif
2022-08-31 19:19:29 -04:00
lod_min = MIN ( lod_min , 8 ) ;
lod_max = MIN ( lod_max , 8 ) ;
2023-06-01 18:32:25 -04:00
for ( int lod = lod_min ; lod < = lod_max ; lod + + ) {
2023-07-31 18:57:52 -04:00
uint32_t * base = & voodoo - > texture_cache [ tmu ] [ c ] . data [ texture_offset [ lod ] ] ;
uint32_t tex_addr = params - > tex_base [ tmu ] [ lod ] & voodoo - > texture_mask ;
int x ;
int y ;
int shift = 8 - params - > tex_lod [ tmu ] [ lod ] ;
const rgba_u * pal ;
2022-08-31 19:19:29 -04:00
2023-07-31 18:57:52 -04:00
#if 0
voodoo_texture_log ( " LOD %i : %08x - %08x %i %i,%i \n " , lod , params - > tex_base [ tmu ] [ lod ] & voodoo - > texture_mask , addr , voodoo - > params . tformat [ tmu ] , voodoo - > params . tex_w_mask [ tmu ] [ lod ] , voodoo - > params . tex_h_mask [ tmu ] [ lod ] ) ;
# endif
2022-08-31 19:19:29 -04:00
switch ( params - > tformat [ tmu ] ) {
case TEX_RGB332 :
for ( y = 0 ; y < voodoo - > params . tex_h_mask [ tmu ] [ lod ] + 1 ; y + + ) {
for ( x = 0 ; x < voodoo - > params . tex_w_mask [ tmu ] [ lod ] + 1 ; x + + ) {
uint8_t dat = voodoo - > tex_mem [ tmu ] [ ( tex_addr + x ) & voodoo - > texture_mask ] ;
base [ x ] = makergba ( rgb332 [ dat ] . r , rgb332 [ dat ] . g , rgb332 [ dat ] . b , 0xff ) ;
}
tex_addr + = ( 1 < < voodoo - > params . tex_shift [ tmu ] [ lod ] ) ;
base + = ( 1 < < shift ) ;
}
break ;
case TEX_Y4I2Q2 :
pal = voodoo - > ncc_lookup [ tmu ] [ ( voodoo - > params . textureMode [ tmu ] & TEXTUREMODE_NCC_SEL ) ? 1 : 0 ] ;
for ( y = 0 ; y < voodoo - > params . tex_h_mask [ tmu ] [ lod ] + 1 ; y + + ) {
for ( x = 0 ; x < voodoo - > params . tex_w_mask [ tmu ] [ lod ] + 1 ; x + + ) {
uint8_t dat = voodoo - > tex_mem [ tmu ] [ ( tex_addr + x ) & voodoo - > texture_mask ] ;
base [ x ] = makergba ( pal [ dat ] . rgba . r , pal [ dat ] . rgba . g , pal [ dat ] . rgba . b , 0xff ) ;
}
tex_addr + = ( 1 < < voodoo - > params . tex_shift [ tmu ] [ lod ] ) ;
base + = ( 1 < < shift ) ;
}
break ;
case TEX_A8 :
for ( y = 0 ; y < voodoo - > params . tex_h_mask [ tmu ] [ lod ] + 1 ; y + + ) {
for ( x = 0 ; x < voodoo - > params . tex_w_mask [ tmu ] [ lod ] + 1 ; x + + ) {
uint8_t dat = voodoo - > tex_mem [ tmu ] [ ( tex_addr + x ) & voodoo - > texture_mask ] ;
2022-02-20 02:26:27 -05:00
2022-08-31 19:19:29 -04:00
base [ x ] = makergba ( dat , dat , dat , dat ) ;
}
tex_addr + = ( 1 < < voodoo - > params . tex_shift [ tmu ] [ lod ] ) ;
base + = ( 1 < < shift ) ;
2020-11-18 00:21:07 +01:00
}
2022-08-31 19:19:29 -04:00
break ;
case TEX_I8 :
for ( y = 0 ; y < voodoo - > params . tex_h_mask [ tmu ] [ lod ] + 1 ; y + + ) {
for ( x = 0 ; x < voodoo - > params . tex_w_mask [ tmu ] [ lod ] + 1 ; x + + ) {
uint8_t dat = voodoo - > tex_mem [ tmu ] [ ( tex_addr + x ) & voodoo - > texture_mask ] ;
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
base [ x ] = makergba ( dat , dat , dat , 0xff ) ;
}
tex_addr + = ( 1 < < voodoo - > params . tex_shift [ tmu ] [ lod ] ) ;
base + = ( 1 < < shift ) ;
}
break ;
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
case TEX_AI8 :
for ( y = 0 ; y < voodoo - > params . tex_h_mask [ tmu ] [ lod ] + 1 ; y + + ) {
for ( x = 0 ; x < voodoo - > params . tex_w_mask [ tmu ] [ lod ] + 1 ; x + + ) {
uint8_t dat = voodoo - > tex_mem [ tmu ] [ ( tex_addr + x ) & voodoo - > texture_mask ] ;
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
base [ x ] = makergba ( ( dat & 0x0f ) | ( ( dat < < 4 ) & 0xf0 ) , ( dat & 0x0f ) | ( ( dat < < 4 ) & 0xf0 ) , ( dat & 0x0f ) | ( ( dat < < 4 ) & 0xf0 ) , ( dat & 0xf0 ) | ( ( dat > > 4 ) & 0x0f ) ) ;
}
tex_addr + = ( 1 < < voodoo - > params . tex_shift [ tmu ] [ lod ] ) ;
base + = ( 1 < < shift ) ;
2020-11-18 00:21:07 +01:00
}
2022-08-31 19:19:29 -04:00
break ;
case TEX_PAL8 :
pal = voodoo - > palette [ tmu ] ;
for ( y = 0 ; y < voodoo - > params . tex_h_mask [ tmu ] [ lod ] + 1 ; y + + ) {
for ( x = 0 ; x < voodoo - > params . tex_w_mask [ tmu ] [ lod ] + 1 ; x + + ) {
uint8_t dat = voodoo - > tex_mem [ tmu ] [ ( tex_addr + x ) & voodoo - > texture_mask ] ;
base [ x ] = makergba ( pal [ dat ] . rgba . r , pal [ dat ] . rgba . g , pal [ dat ] . rgba . b , 0xff ) ;
}
tex_addr + = ( 1 < < voodoo - > params . tex_shift [ tmu ] [ lod ] ) ;
base + = ( 1 < < shift ) ;
}
break ;
case TEX_APAL8 :
pal = voodoo - > palette [ tmu ] ;
for ( y = 0 ; y < voodoo - > params . tex_h_mask [ tmu ] [ lod ] + 1 ; y + + ) {
for ( x = 0 ; x < voodoo - > params . tex_w_mask [ tmu ] [ lod ] + 1 ; x + + ) {
uint8_t dat = voodoo - > tex_mem [ tmu ] [ ( tex_addr + x ) & voodoo - > texture_mask ] ;
int r = ( ( pal [ dat ] . rgba . r & 3 ) < < 6 ) | ( ( pal [ dat ] . rgba . g & 0xf0 ) > > 2 ) | ( pal [ dat ] . rgba . r & 3 ) ;
int g = ( ( pal [ dat ] . rgba . g & 0xf ) < < 4 ) | ( ( pal [ dat ] . rgba . b & 0xc0 ) > > 4 ) | ( ( pal [ dat ] . rgba . g & 0xf ) > > 2 ) ;
int b = ( ( pal [ dat ] . rgba . b & 0x3f ) < < 2 ) | ( ( pal [ dat ] . rgba . b & 0x30 ) > > 4 ) ;
int a = ( pal [ dat ] . rgba . r & 0xfc ) | ( ( pal [ dat ] . rgba . r & 0xc0 ) > > 6 ) ;
base [ x ] = makergba ( r , g , b , a ) ;
}
tex_addr + = ( 1 < < voodoo - > params . tex_shift [ tmu ] [ lod ] ) ;
base + = ( 1 < < shift ) ;
}
break ;
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
case TEX_ARGB8332 :
for ( y = 0 ; y < voodoo - > params . tex_h_mask [ tmu ] [ lod ] + 1 ; y + + ) {
for ( x = 0 ; x < voodoo - > params . tex_w_mask [ tmu ] [ lod ] + 1 ; x + + ) {
uint16_t dat = * ( uint16_t * ) & voodoo - > tex_mem [ tmu ] [ ( tex_addr + x * 2 ) & voodoo - > texture_mask ] ;
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
base [ x ] = makergba ( rgb332 [ dat & 0xff ] . r , rgb332 [ dat & 0xff ] . g , rgb332 [ dat & 0xff ] . b , dat > > 8 ) ;
}
tex_addr + = ( 1 < < ( voodoo - > params . tex_shift [ tmu ] [ lod ] + 1 ) ) ;
base + = ( 1 < < shift ) ;
}
break ;
case TEX_A8Y4I2Q2 :
pal = voodoo - > ncc_lookup [ tmu ] [ ( voodoo - > params . textureMode [ tmu ] & TEXTUREMODE_NCC_SEL ) ? 1 : 0 ] ;
for ( y = 0 ; y < voodoo - > params . tex_h_mask [ tmu ] [ lod ] + 1 ; y + + ) {
for ( x = 0 ; x < voodoo - > params . tex_w_mask [ tmu ] [ lod ] + 1 ; x + + ) {
uint16_t dat = * ( uint16_t * ) & voodoo - > tex_mem [ tmu ] [ ( tex_addr + x * 2 ) & voodoo - > texture_mask ] ;
base [ x ] = makergba ( pal [ dat & 0xff ] . rgba . r , pal [ dat & 0xff ] . rgba . g , pal [ dat & 0xff ] . rgba . b , dat > > 8 ) ;
}
tex_addr + = ( 1 < < ( voodoo - > params . tex_shift [ tmu ] [ lod ] + 1 ) ) ;
base + = ( 1 < < shift ) ;
}
break ;
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
case TEX_R5G6B5 :
for ( y = 0 ; y < voodoo - > params . tex_h_mask [ tmu ] [ lod ] + 1 ; y + + ) {
for ( x = 0 ; x < voodoo - > params . tex_w_mask [ tmu ] [ lod ] + 1 ; x + + ) {
uint16_t dat = * ( uint16_t * ) & voodoo - > tex_mem [ tmu ] [ ( tex_addr + x * 2 ) & voodoo - > texture_mask ] ;
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
base [ x ] = makergba ( rgb565 [ dat ] . r , rgb565 [ dat ] . g , rgb565 [ dat ] . b , 0xff ) ;
}
tex_addr + = ( 1 < < ( voodoo - > params . tex_shift [ tmu ] [ lod ] + 1 ) ) ;
base + = ( 1 < < shift ) ;
}
break ;
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
case TEX_ARGB1555 :
for ( y = 0 ; y < voodoo - > params . tex_h_mask [ tmu ] [ lod ] + 1 ; y + + ) {
for ( x = 0 ; x < voodoo - > params . tex_w_mask [ tmu ] [ lod ] + 1 ; x + + ) {
uint16_t dat = * ( uint16_t * ) & voodoo - > tex_mem [ tmu ] [ ( tex_addr + x * 2 ) & voodoo - > texture_mask ] ;
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
base [ x ] = makergba ( argb1555 [ dat ] . r , argb1555 [ dat ] . g , argb1555 [ dat ] . b , argb1555 [ dat ] . a ) ;
}
tex_addr + = ( 1 < < ( voodoo - > params . tex_shift [ tmu ] [ lod ] + 1 ) ) ;
base + = ( 1 < < shift ) ;
}
break ;
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
case TEX_ARGB4444 :
for ( y = 0 ; y < voodoo - > params . tex_h_mask [ tmu ] [ lod ] + 1 ; y + + ) {
for ( x = 0 ; x < voodoo - > params . tex_w_mask [ tmu ] [ lod ] + 1 ; x + + ) {
uint16_t dat = * ( uint16_t * ) & voodoo - > tex_mem [ tmu ] [ ( tex_addr + x * 2 ) & voodoo - > texture_mask ] ;
base [ x ] = makergba ( argb4444 [ dat ] . r , argb4444 [ dat ] . g , argb4444 [ dat ] . b , argb4444 [ dat ] . a ) ;
}
tex_addr + = ( 1 < < ( voodoo - > params . tex_shift [ tmu ] [ lod ] + 1 ) ) ;
base + = ( 1 < < shift ) ;
}
break ;
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
case TEX_A8I8 :
for ( y = 0 ; y < voodoo - > params . tex_h_mask [ tmu ] [ lod ] + 1 ; y + + ) {
for ( x = 0 ; x < voodoo - > params . tex_w_mask [ tmu ] [ lod ] + 1 ; x + + ) {
uint16_t dat = * ( uint16_t * ) & voodoo - > tex_mem [ tmu ] [ ( tex_addr + x * 2 ) & voodoo - > texture_mask ] ;
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
base [ x ] = makergba ( dat & 0xff , dat & 0xff , dat & 0xff , dat > > 8 ) ;
}
tex_addr + = ( 1 < < ( voodoo - > params . tex_shift [ tmu ] [ lod ] + 1 ) ) ;
base + = ( 1 < < shift ) ;
2020-11-18 00:21:07 +01:00
}
2022-08-31 19:19:29 -04:00
break ;
case TEX_APAL88 :
pal = voodoo - > palette [ tmu ] ;
for ( y = 0 ; y < voodoo - > params . tex_h_mask [ tmu ] [ lod ] + 1 ; y + + ) {
for ( x = 0 ; x < voodoo - > params . tex_w_mask [ tmu ] [ lod ] + 1 ; x + + ) {
uint16_t dat = * ( uint16_t * ) & voodoo - > tex_mem [ tmu ] [ ( tex_addr + x * 2 ) & voodoo - > texture_mask ] ;
base [ x ] = makergba ( pal [ dat & 0xff ] . rgba . r , pal [ dat & 0xff ] . rgba . g , pal [ dat & 0xff ] . rgba . b , dat > > 8 ) ;
}
tex_addr + = ( 1 < < ( voodoo - > params . tex_shift [ tmu ] [ lod ] + 1 ) ) ;
base + = ( 1 < < shift ) ;
}
break ;
default :
fatal ( " Unknown texture format %i \n " , params - > tformat [ tmu ] ) ;
}
}
voodoo - > texture_cache [ tmu ] [ c ] . is16 = voodoo - > params . tformat [ tmu ] & 8 ;
if ( params - > tformat [ tmu ] = = TEX_PAL8 | | params - > tformat [ tmu ] = = TEX_APAL8 | | params - > tformat [ tmu ] = = TEX_APAL88 )
voodoo - > texture_cache [ tmu ] [ c ] . palette_checksum = palette_checksum ;
else
voodoo - > texture_cache [ tmu ] [ c ] . palette_checksum = 0 ;
if ( lod_min = = 0 ) {
voodoo - > texture_cache [ tmu ] [ c ] . addr_start [ 0 ] = voodoo - > params . tex_base [ tmu ] [ 0 ] ;
voodoo - > texture_cache [ tmu ] [ c ] . addr_end [ 0 ] = voodoo - > params . tex_end [ tmu ] [ 0 ] ;
} else
voodoo - > texture_cache [ tmu ] [ c ] . addr_start [ 0 ] = voodoo - > texture_cache [ tmu ] [ c ] . addr_end [ 0 ] = 0 ;
if ( lod_min < = 1 & & lod_max > = 1 ) {
voodoo - > texture_cache [ tmu ] [ c ] . addr_start [ 1 ] = voodoo - > params . tex_base [ tmu ] [ 1 ] ;
voodoo - > texture_cache [ tmu ] [ c ] . addr_end [ 1 ] = voodoo - > params . tex_end [ tmu ] [ 1 ] ;
} else
voodoo - > texture_cache [ tmu ] [ c ] . addr_start [ 1 ] = voodoo - > texture_cache [ tmu ] [ c ] . addr_end [ 1 ] = 0 ;
if ( lod_min < = 2 & & lod_max > = 2 ) {
voodoo - > texture_cache [ tmu ] [ c ] . addr_start [ 2 ] = voodoo - > params . tex_base [ tmu ] [ 2 ] ;
voodoo - > texture_cache [ tmu ] [ c ] . addr_end [ 2 ] = voodoo - > params . tex_end [ tmu ] [ 2 ] ;
} else
voodoo - > texture_cache [ tmu ] [ c ] . addr_start [ 2 ] = voodoo - > texture_cache [ tmu ] [ c ] . addr_end [ 2 ] = 0 ;
if ( lod_max > = 3 ) {
voodoo - > texture_cache [ tmu ] [ c ] . addr_start [ 3 ] = voodoo - > params . tex_base [ tmu ] [ ( lod_min > 3 ) ? lod_min : 3 ] ;
voodoo - > texture_cache [ tmu ] [ c ] . addr_end [ 3 ] = voodoo - > params . tex_end [ tmu ] [ ( lod_max < 8 ) ? lod_max : 8 ] ;
} else
voodoo - > texture_cache [ tmu ] [ c ] . addr_start [ 3 ] = voodoo - > texture_cache [ tmu ] [ c ] . addr_end [ 3 ] = 0 ;
2023-06-01 18:32:25 -04:00
for ( uint8_t d = 0 ; d < 4 ; d + + ) {
2022-08-31 19:19:29 -04:00
addr = voodoo - > texture_cache [ tmu ] [ c ] . addr_start [ d ] ;
addr_end = voodoo - > texture_cache [ tmu ] [ c ] . addr_end [ d ] ;
if ( addr_end ! = 0 ) {
for ( ; addr < = addr_end ; addr + = ( 1 < < TEX_DIRTY_SHIFT ) )
voodoo - > texture_present [ tmu ] [ ( addr & voodoo - > texture_mask ) > > TEX_DIRTY_SHIFT ] = 1 ;
2020-11-18 00:21:07 +01:00
}
2022-08-31 19:19:29 -04:00
}
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
params - > tex_entry [ tmu ] = c ;
voodoo - > texture_cache [ tmu ] [ c ] . refcount + + ;
2020-11-18 00:21:07 +01:00
}
2022-08-31 19:19:29 -04:00
void
flush_texture_cache ( voodoo_t * voodoo , uint32_t dirty_addr , int tmu )
2020-11-18 00:21:07 +01:00
{
2022-08-31 19:19:29 -04:00
int wait_for_idle = 0 ;
memset ( voodoo - > texture_present [ tmu ] , 0 , sizeof ( voodoo - > texture_present [ 0 ] ) ) ;
2023-06-28 13:46:28 -04:00
#if 0
voodoo_texture_log ( " Evict %08x %i \n " , dirty_addr , sizeof ( voodoo - > texture_present ) ) ;
# endif
2023-06-01 18:32:25 -04:00
for ( uint8_t c = 0 ; c < TEX_CACHE_MAX ; c + + ) {
2022-08-31 19:19:29 -04:00
if ( voodoo - > texture_cache [ tmu ] [ c ] . base ! = - 1 ) {
2023-06-01 18:32:25 -04:00
for ( uint8_t d = 0 ; d < 4 ; d + + ) {
2022-08-31 19:19:29 -04:00
int addr_start = voodoo - > texture_cache [ tmu ] [ c ] . addr_start [ d ] ;
int addr_end = voodoo - > texture_cache [ tmu ] [ c ] . addr_end [ d ] ;
if ( addr_end ! = 0 ) {
int addr_start_masked = addr_start & voodoo - > texture_mask & ~ 0x3ff ;
int addr_end_masked = ( ( addr_end & voodoo - > texture_mask ) + 0x3ff ) & ~ 0x3ff ;
if ( addr_end_masked < addr_start_masked )
addr_end_masked = voodoo - > texture_mask + 1 ;
if ( dirty_addr > = addr_start_masked & & dirty_addr < addr_end_masked ) {
2023-07-31 18:57:52 -04:00
#if 0
voodoo_texture_log ( " Evict texture %i %08x \n " , c , voodoo - > texture_cache [ tmu ] [ c ] . base ) ;
# endif
2022-08-31 19:19:29 -04:00
if ( voodoo - > texture_cache [ tmu ] [ c ] . refcount ! = voodoo - > texture_cache [ tmu ] [ c ] . refcount_r [ 0 ] | | ( voodoo - > render_threads = = 2 & & voodoo - > texture_cache [ tmu ] [ c ] . refcount ! = voodoo - > texture_cache [ tmu ] [ c ] . refcount_r [ 1 ] ) )
wait_for_idle = 1 ;
voodoo - > texture_cache [ tmu ] [ c ] . base = - 1 ;
} else {
for ( ; addr_start < = addr_end ; addr_start + = ( 1 < < TEX_DIRTY_SHIFT ) )
voodoo - > texture_present [ tmu ] [ ( addr_start & voodoo - > texture_mask ) > > TEX_DIRTY_SHIFT ] = 1 ;
}
2020-11-18 00:21:07 +01:00
}
2022-08-31 19:19:29 -04:00
}
2020-11-18 00:21:07 +01:00
}
2022-08-31 19:19:29 -04:00
}
if ( wait_for_idle )
voodoo_wait_for_render_thread_idle ( voodoo ) ;
2020-11-18 00:21:07 +01:00
}
2022-08-31 19:19:29 -04:00
void
2023-06-09 23:46:54 -04:00
voodoo_tex_writel ( uint32_t addr , uint32_t val , void * priv )
2020-11-18 00:21:07 +01:00
{
2023-06-01 18:32:25 -04:00
int lod ;
int s ;
int t ;
2023-06-09 23:46:54 -04:00
voodoo_t * voodoo = ( voodoo_t * ) priv ;
2022-08-31 19:19:29 -04:00
int tmu ;
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
if ( addr & 0x400000 )
return ; /*TREX != 0*/
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
tmu = ( addr & 0x200000 ) ? 1 : 0 ;
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
if ( tmu & & ! voodoo - > dual_tmus )
return ;
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
if ( voodoo - > type < VOODOO_BANSHEE ) {
if ( ! ( voodoo - > params . tformat [ tmu ] & 8 ) & & voodoo - > type > = VOODOO_BANSHEE ) {
lod = ( addr > > 16 ) & 0xf ;
t = ( addr > > 8 ) & 0xff ;
} else {
lod = ( addr > > 17 ) & 0xf ;
t = ( addr > > 9 ) & 0xff ;
}
if ( voodoo - > params . tformat [ tmu ] & 8 )
s = ( addr > > 1 ) & 0xfe ;
else {
if ( ( voodoo - > params . textureMode [ tmu ] & ( 1 < < 31 ) ) | | voodoo - > type > = VOODOO_BANSHEE )
s = addr & 0xfc ;
else
s = ( addr > > 1 ) & 0xfc ;
}
if ( lod > LOD_MAX )
return ;
2020-11-18 00:21:07 +01:00
2023-06-28 13:46:28 -04:00
#if 0
if ( addr > = 0x200000 )
return ;
# endif
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
if ( voodoo - > params . tformat [ tmu ] & 8 )
addr = voodoo - > params . tex_base [ tmu ] [ lod ] + s * 2 + ( t < < voodoo - > params . tex_shift [ tmu ] [ lod ] ) * 2 ;
2020-11-18 00:21:07 +01:00
else
2022-08-31 19:19:29 -04:00
addr = voodoo - > params . tex_base [ tmu ] [ lod ] + s + ( t < < voodoo - > params . tex_shift [ tmu ] [ lod ] ) ;
} else
addr = ( addr & 0x1ffffc ) + voodoo - > params . tex_base [ tmu ] [ 0 ] ;
2020-11-18 00:21:07 +01:00
2022-08-31 19:19:29 -04:00
if ( voodoo - > texture_present [ tmu ] [ ( addr & voodoo - > texture_mask ) > > TEX_DIRTY_SHIFT ] ) {
2023-06-28 13:46:28 -04:00
#if 0
voodoo_texture_log ( " texture_present at %08x %i \n " , addr , ( addr & voodoo - > texture_mask ) > > TEX_DIRTY_SHIFT ) ;
# endif
2022-08-31 19:19:29 -04:00
flush_texture_cache ( voodoo , addr & voodoo - > texture_mask , tmu ) ;
}
if ( voodoo - > type = = VOODOO_3 & & voodoo - > texture_present [ tmu ^ 1 ] [ ( addr & voodoo - > texture_mask ) > > TEX_DIRTY_SHIFT ] ) {
2023-06-28 13:46:28 -04:00
#if 0
voodoo_texture_log ( " texture_present at %08x %i \n " , addr , ( addr & voodoo - > texture_mask ) > > TEX_DIRTY_SHIFT ) ;
# endif
2022-08-31 19:19:29 -04:00
flush_texture_cache ( voodoo , addr & voodoo - > texture_mask , tmu ^ 1 ) ;
}
* ( uint32_t * ) ( & voodoo - > tex_mem [ tmu ] [ addr & voodoo - > texture_mask ] ) = val ;
2020-11-18 00:21:07 +01:00
}