diff --git a/src/cpu/i960/i960.c b/src/cpu/i960/i960.c index 1b51feef..c92a1e98 100644 --- a/src/cpu/i960/i960.c +++ b/src/cpu/i960/i960.c @@ -120,9 +120,33 @@ static INLINE int i960_is_burst( UINT32 address ) return i960_burst_cb == NULL || i960_burst_cb( address ); } +/* port: the opcodes are read straight from the memory block of the last + fetch (ROM, RAM or a bank: what cpu_readmem32ledw_dword reads there); + anything else goes through the memory system. Forgotten at every + timeslice, as the banks are only set up between them */ +static UINT32 i960_fetch_start, i960_fetch_len; +static const UINT8 *i960_fetch_ptr; + +static UINT32 i960_readop_slow( UINT32 address ) +{ + offs_t start, len; + const UINT8 *p = (const UINT8 *)memory_get_read_range( cpu_getactivecpu(), address, &start, &len ); + if( p != NULL ) + { + /* the block in the CPU's addresses (the mask only drops high bits) */ + i960_fetch_start = address - ( ( address & mem_amask ) - start ); + i960_fetch_len = len; + i960_fetch_ptr = p; + } + return cpu_readmem32ledw_dword( address ); +} + static INLINE UINT32 i960_readop( UINT32 address ) { - return cpu_readmem32ledw_dword( address ); + UINT32 off = address - i960_fetch_start; + if( off < i960_fetch_len ) + return *(const data32_t *)( i960_fetch_ptr + ( off & ~3 ) ); + return i960_readop_slow( address ); } static void i960_fatal( const char *fmt, ... ) @@ -880,7 +904,14 @@ static void execute_burst_stall_op(UINT32 opcode) check_immediate_irqs(); } -static void execute_op(UINT32 opcode) +/* port: inlined in its only caller, the i960_execute loop: as a function, + saving and restoring its registers on every instruction cost a fifth of + the time spent in the CPU */ +#if defined(__GNUC__) +static INLINE __attribute__((always_inline)) void execute_op(UINT32 opcode) +#else +static INLINE void execute_op(UINT32 opcode) +#endif { UINT32 t1, t2; double t1f, t2f; @@ -2521,6 +2552,7 @@ int i960_execute( int cycles ) UINT32 opcode; i960_icount = cycles; + i960_fetch_len = 0; /* delay checking irqs if we are in burst stall mode */ if( m_stall_state.burst_mode == 0 ) diff --git a/src/cpu/sharc/sharc.c b/src/cpu/sharc/sharc.c index e13b5858..b449f5a8 100644 --- a/src/cpu/sharc/sharc.c +++ b/src/cpu/sharc/sharc.c @@ -1188,7 +1188,8 @@ int sharc_execute(int cycles) } } - if (!m_core->write_stalled) + /* port: no call when channels 6 and 7 are idle (most instructions) */ + if (!m_core->write_stalled && (m_core->dma_status & ((1 << 6) | (1 << 7)))) { dma_stalled = dma_run_cycle(6); dma_stalled |= dma_run_cycle(7); diff --git a/src/drivers/model2.c b/src/drivers/model2.c index 5b32c4d0..8674529a 100644 --- a/src/drivers/model2.c +++ b/src/drivers/model2.c @@ -37,6 +37,42 @@ data32_t *model2_bufferram; static data32_t *model2_backup1; data32_t *model2_textureram0; data32_t *model2_textureram1; +UINT8 *model2_texdec0; +UINT8 *model2_texdec1; + +/* + The texture sheets taken apart, one byte per texel, for the renderer + (fetch_bilinear_texel): a 32-bit word of texture RAM holds two 2x2 + blocks of 4-bit texels. Its texels are at x = xbase + 0..3 and + y = ybase + 0..1 of the 2048x1024 sheet, the rows of the columns past + 1024 being folded into the upper half of the RAM; within the word, bit 1 + of x picks the block and the parity of x and y the texel. The byte array + is indexed y * 2048 + x and is rebuilt with every write. +*/ +static void model2_tex_decode( UINT8 *dec, UINT32 index, UINT32 word ) +{ + UINT32 r = ( index >> 8 ) & 0x3ff, xa = index & 0xff; + UINT32 xbase = ( r < 512 ) ? xa * 4 : 1024 + xa * 4; + UINT32 ybase = ( r < 512 ) ? r * 2 : r * 2 - 1024; + int j, k; + for( j = 0; j < 2; j++ ) + for( k = 0; k < 4; k++ ) + { + UINT32 x = xbase + k, y = ybase + j; + UINT32 shift = ( ( x & 2 ) << 3 ) | ( ( ~x & 1 ) << 2 ) | ( ( ~y & 1 ) << 3 ); + dec[ y * 2048 + x ] = ( word >> shift ) & 0x0f; + } +} + +static void model2_tex_decode_all( void ) +{ + UINT32 i; + for( i = 0; i < 0x40000; i++ ) + { + model2_tex_decode( model2_texdec0, i, model2_textureram0[ i ] ); + model2_tex_decode( model2_texdec1, i, model2_textureram1[ i ] ); + } +} data16_t *model2_palram; data16_t *model2_colorxlat; UINT8 *model2_lumaram; @@ -637,6 +673,7 @@ static WRITE32_HANDLER( tex0_w ) model2_textureram0[ offset >> 1 ] = ( model2_textureram0[ offset >> 1 ] & 0xffff0000 ) | ( data & 0xffff ); else model2_textureram0[ offset >> 1 ] = ( model2_textureram0[ offset >> 1 ] & 0x0000ffff ) | ( ( data & 0xffff ) << 16 ); + model2_tex_decode( model2_texdec0, offset >> 1, model2_textureram0[ offset >> 1 ] ); } static WRITE32_HANDLER( tex1_w ) @@ -646,6 +683,7 @@ static WRITE32_HANDLER( tex1_w ) model2_textureram1[ offset >> 1 ] = ( model2_textureram1[ offset >> 1 ] & 0xffff0000 ) | ( data & 0xffff ); else model2_textureram1[ offset >> 1 ] = ( model2_textureram1[ offset >> 1 ] & 0x0000ffff ) | ( ( data & 0xffff ) << 16 ); + model2_tex_decode( model2_texdec1, offset >> 1, model2_textureram1[ offset >> 1 ] ); } static READ32_HANDLER( tex0_r ) @@ -672,6 +710,7 @@ static WRITE32_HANDLER( tex2b_w ) { data32_t *ram = ( offset & 0x80000 ) ? model2_textureram1 : model2_textureram0; COMBINE_DATA( &ram[ offset & 0x3ffff ] ); + model2_tex_decode( ( offset & 0x80000 ) ? model2_texdec1 : model2_texdec0, offset & 0x3ffff, ram[ offset & 0x3ffff ] ); } static READ32_HANDLER( luma2b_r ) @@ -1750,6 +1789,7 @@ static void model2_postload( void ) { int i; model2_sound_postload(); + model2_tex_decode_all(); m_palette_dirty = 1; model2_palette_refresh(); for( i = 0; i < 4; i++ ) @@ -1779,6 +1819,8 @@ static DRIVER_INIT( model2a ) model2_backup1 = auto_malloc( 0x4000 ); model2_textureram0 = auto_malloc( 0x100000 ); model2_textureram1 = auto_malloc( 0x100000 ); + model2_texdec0 = auto_malloc( 2048 * 1024 ); + model2_texdec1 = auto_malloc( 2048 * 1024 ); model2_palram = auto_malloc( 0x4000 ); model2_colorxlat = auto_malloc( 0xc000 ); model2_lumaram = auto_malloc( 0x8000 ); @@ -1786,6 +1828,8 @@ static DRIVER_INIT( model2a ) memset( model2_ram2, 0, 0x40000 ); memset( model2_textureram0, 0, 0x100000 ); memset( model2_textureram1, 0, 0x100000 ); + memset( model2_texdec0, 0, 2048 * 1024 ); + memset( model2_texdec1, 0, 2048 * 1024 ); memset( model2_palram, 0, 0x4000 ); memset( model2_colorxlat, 0, 0xc000 ); memset( model2_lumaram, 0, 0x8000 ); diff --git a/src/includes/model2.h b/src/includes/model2.h index a2c4812a..388754df 100644 --- a/src/includes/model2.h +++ b/src/includes/model2.h @@ -11,6 +11,8 @@ extern data32_t *model2_bufferram; extern data32_t *model2_textureram0; extern data32_t *model2_textureram1; +extern UINT8 *model2_texdec0; /* the sheets one byte per texel, y * 2048 + x */ +extern UINT8 *model2_texdec1; extern data16_t *model2_palram; extern data16_t *model2_colorxlat; extern UINT8 *model2_lumaram; diff --git a/src/mame-memory.c b/src/mame-memory.c index 64f3438d..ae062491 100644 --- a/src/mame-memory.c +++ b/src/mame-memory.c @@ -777,6 +777,53 @@ void *memory_get_read_ptr(int cpunum, offs_t offset) } +/*------------------------------------------------- + memory_get_read_range - like memory_get_read_ptr, + also giving the range of addresses around the + offset read from the same memory (*start, *len, + masked addresses); NULL when the offset is not + plain memory +-------------------------------------------------*/ + +void *memory_get_read_range(int cpunum, offs_t offset, offs_t *start, offs_t *len) +{ + struct memport_data *memport = &cpudata[cpunum].mem; + struct handler_data *handlist = (memport->dbits == 32) ? rmemhandler32 : (memport->dbits == 16) ? rmemhandler16 : rmemhandler8; + UINT8 minbits = memport->abits - memport->ebits; + int l2bits = LEVEL2_BITS(memport->abits - minbits); + UINT8 entry; + offs_t first, last; + + offset &= memport->mask; + entry = memport->read.table[LEVEL1_INDEX(offset, memport->abits, minbits)]; + if (entry >= SUBTABLE_BASE) + { + /* the run of the same entry in the subtable, at most 4 KB each side */ + UINT8 sub = entry; + offs_t base = offset & ~(((offs_t)1 << (l2bits + minbits)) - 1); + offs_t i = (offset - base) >> minbits, n = (offs_t)1 << l2bits, j; + offs_t lim = 0x1000 >> minbits; + entry = memport->read.table[LEVEL2_INDEX(sub, offset, memport->abits, minbits)]; + for (j = i; j > 0 && i - j < lim && memport->read.table[LEVEL2_INDEX(sub, base + ((j - 1) << minbits), memport->abits, minbits)] == entry; j--) ; + first = base + (j << minbits); + for (j = i; j + 1 < n && j - i < lim && memport->read.table[LEVEL2_INDEX(sub, base + ((j + 1) << minbits), memport->abits, minbits)] == entry; j++) ; + last = base + (j << minbits) + (((offs_t)1 << minbits) - 1); + } + else + { + first = offset & ~(((offs_t)1 << (l2bits + minbits)) - 1); + last = first + (((offs_t)1 << (l2bits + minbits)) - 1); + } + + /* 8-bit case: RAM/ROM/RAMROM */ + if (entry > STATIC_RAM || (minbits == 0 && entry != STATIC_RAM)) + return NULL; + *start = first; + *len = last - first + 1; + return &cpu_bankbase[entry][first - handlist[entry].offset]; +} + + /*------------------------------------------------- memory_get_write_ptr - return a pointer to the base of RAM associated with the given CPU diff --git a/src/memory.h b/src/memory.h index 1b1e78cb..24d8e6bc 100644 --- a/src/memory.h +++ b/src/memory.h @@ -825,6 +825,7 @@ extern offs_t encrypted_opcode_start[],encrypted_opcode_end[]; /* ----- return a base pointer to memory ---- */ void * memory_find_base(int cpunum, offs_t offset); void * memory_get_read_ptr(int cpunum, offs_t offset); +void * memory_get_read_range(int cpunum, offs_t offset, offs_t *start, offs_t *len); void * memory_get_write_ptr(int cpunum, offs_t offset); /* ----- dynamic memory mapping ----- */ diff --git a/src/sound/scsp.c b/src/sound/scsp.c index 3d2faf5e..b270f8c8 100644 --- a/src/sound/scsp.c +++ b/src/sound/scsp.c @@ -815,6 +815,7 @@ static void SCSP_w16(unsigned int addr,unsigned short val) else if(addr>=0x800) { SCSP->DSP.MPRO[(addr-0x800)/2]=val; + SCSP->DSP.Dirty=1; if(addr==0xbf0) SCSPDSP_Start(&SCSP->DSP); } @@ -1208,6 +1209,8 @@ static void SCSP_presave(void) int i, s; for (i = 0; i < 3; i++) SCSP_timer_left[i] = SCSP_timer[i] ? timer_timeleft(SCSP_timer[i]) : TIME_NEVER; + for (i = 0; i < MAX_SCSP; i++) + SCSPs[i].DSP.Dirty = 1; /* MPRO was loaded */ for (i = 0; i < MAX_SCSP; i++) for (s = 0; s < 32; s++) { @@ -1230,6 +1233,8 @@ static void SCSP_postload(void) else timer_adjust(SCSP_timer[i], TIME_NEVER, i, 0); } + for (i = 0; i < MAX_SCSP; i++) + SCSPs[i].DSP.Dirty = 1; /* MPRO was loaded */ for (i = 0; i < MAX_SCSP; i++) for (s = 0; s < 32; s++) { diff --git a/src/sound/scspdsp.c b/src/sound/scspdsp.c index a3c1ad3b..199c6489 100644 --- a/src/sound/scspdsp.c +++ b/src/sound/scspdsp.c @@ -36,6 +36,19 @@ struct _SCSPDSP int Stopped; int LastStep; + + /* port: the steps that only multiply and accumulate (no write to TEMP, + MEMS, FRC, Y, ADRS, EFREG or the delay RAM), decoded from MPRO when + it changes (Dirty) and run by a short path in SCSPDSP_Step */ + int Dirty; + struct + { + UINT8 mac; /* the step is one of them */ + UINT8 tra, ira, coef; + UINT8 xsel, ysel; + UINT8 bsel; /* 0: zero, 1: ACC, 2: TEMP */ + UINT8 negb; + } MAC[128]; }; /* sign-extend the low "bits" bits of v */ @@ -53,22 +66,29 @@ static INLINE INT32 SCSPDSP_clamp24( INT32 v ) return v; } +/* port: leading zeros of a 12-bit value (12 for 0), for SCSPDSP_PACK */ +static UINT8 SCSPDSP_lz12[ 4096 ]; + +static void SCSPDSP_InitTables( void ) +{ + int i; + for( i = 0; i < 4096; i++ ) + { + int n = 0; + while( n < 12 && !( i & ( 0x800 >> n ) ) ) + n++; + SCSPDSP_lz12[ i ] = n; + } +} + /* 24 bit value to the 16 bit floating point format of the delay RAM */ static UINT16 SCSPDSP_PACK( INT32 val ) { UINT32 uval = (UINT32)val; UINT32 sign = ( uval >> 23 ) & 1; UINT32 temp = ( uval ^ ( uval << 1 ) ) & 0xffffff; - UINT32 exponent = 0; - int k; - - for( k = 0; k < 12; k++ ) - { - if( temp & 0x800000 ) - break; - temp <<= 1; - exponent += 1; - } + /* the leading zeros of bits 23-12, up to 12 */ + UINT32 exponent = SCSPDSP_lz12[ temp >> 12 ]; if( exponent < 12 ) uval = ( uval << exponent ) & 0x3fffff; else @@ -103,11 +123,45 @@ static INT32 SCSPDSP_UNPACK( UINT16 val ) static void SCSPDSP_Init( struct _SCSPDSP *DSP, UINT16 *ram, UINT32 ramsize ) { + SCSPDSP_InitTables(); memset( DSP, 0, sizeof( *DSP ) ); DSP->RAM = ram; DSP->RAMmask = ( ramsize / 2 ) - 1; DSP->RBL = 8 * 1024; DSP->Stopped = 1; + DSP->Dirty = 1; +} + +static void SCSPDSP_Decode( struct _SCSPDSP *DSP ) +{ + int step; + + for( step = 0; step < 128; ++step ) + { + UINT16 *IPtr = DSP->MPRO + ( step * 4 ); + UINT32 TWT = ( IPtr[0] >> 7 ) & 0x01; + UINT32 IRA = ( IPtr[1] >> 6 ) & 0x3f; + UINT32 IWT = ( IPtr[1] >> 5 ) & 0x01; + UINT32 MWT = ( IPtr[2] >> 14 ) & 0x01; + UINT32 MRD = ( IPtr[2] >> 13 ) & 0x01; + UINT32 EWT = ( IPtr[2] >> 12 ) & 0x01; + UINT32 ADRL = ( IPtr[2] >> 7 ) & 0x01; + UINT32 FRCL = ( IPtr[2] >> 6 ) & 0x01; + UINT32 YRL = ( IPtr[2] >> 3 ) & 0x01; + UINT32 ZERO = ( IPtr[2] >> 1 ) & 0x01; + UINT32 BSEL = ( IPtr[2] >> 0 ) & 0x01; + + DSP->MAC[step].mac = !TWT && !IWT && !EWT && !ADRL && !FRCL && !YRL && IRA <= 0x31 && + !( ( MRD || MWT ) && ( step & 1 ) ); + DSP->MAC[step].tra = ( IPtr[0] >> 8 ) & 0x7f; + DSP->MAC[step].ira = IRA; + DSP->MAC[step].coef = ( IPtr[3] >> 9 ) & 0x3f; + DSP->MAC[step].xsel = ( IPtr[1] >> 15 ) & 0x01; + DSP->MAC[step].ysel = ( IPtr[1] >> 13 ) & 0x03; + DSP->MAC[step].bsel = ZERO ? 0 : BSEL ? 1 : 2; + DSP->MAC[step].negb = ( IPtr[2] >> 2 ) & 0x01; + } + DSP->Dirty = 0; } static void SCSPDSP_Step( struct _SCSPDSP *DSP ) @@ -130,8 +184,59 @@ static void SCSPDSP_Step( struct _SCSPDSP *DSP ) memset( DSP->EFREG, 0, sizeof( DSP->EFREG ) ); + if( DSP->Dirty ) + SCSPDSP_Decode( DSP ); + for( step = 0; step < DSP->LastStep; ++step ) { + if( DSP->MAC[step].mac ) + { + /* the same as below for such a step: the shifter output and + INPUTS are not used */ + INT32 TEMPV = 0; + UINT32 ysel = DSP->MAC[step].ysel; + + if( !DSP->MAC[step].xsel || DSP->MAC[step].bsel == 2 ) + TEMPV = SCSPDSP_sext( DSP->TEMP[( DSP->MAC[step].tra + DSP->DEC ) & 0x7f], 24 ); + + if( DSP->MAC[step].xsel ) + { + UINT32 IRA = DSP->MAC[step].ira; + if( IRA <= 0x1f ) + X = DSP->MEMS[IRA]; + else if( IRA <= 0x2f ) + X = DSP->MIXS[IRA - 0x20] << 4; + else + X = DSP->EXTS[IRA - 0x30] << 8; + X = SCSPDSP_sext( X, 24 ); + } + else + X = TEMPV; + + if( DSP->MAC[step].bsel == 0 ) + B = 0; + else + { + B = DSP->MAC[step].bsel == 1 ? ACC : TEMPV; + if( DSP->MAC[step].negb ) + B = 0 - B; + } + + if( ysel == 0 ) + Y = FRC_REG; + else if( ysel == 1 ) + Y = DSP->COEF[DSP->MAC[step].coef] >> 3; + else if( ysel == 2 ) + Y = ( Y_REG >> 11 ) & 0x1fff; + else + Y = ( Y_REG >> 4 ) & 0x0fff; + Y = SCSPDSP_sext( Y, 13 ); + + ACC = (INT32)( ( ( (INT64)X * (INT64)Y ) >> 12 ) + B ); + continue; + } + + { UINT16 *IPtr = DSP->MPRO + ( step * 4 ); UINT32 TRA = ( IPtr[0] >> 8 ) & 0x7f; @@ -284,6 +389,7 @@ static void SCSPDSP_Step( struct _SCSPDSP *DSP ) if( EWT ) DSP->EFREG[EWA] += SHIFTED >> 8; + } } --DSP->DEC; memset( DSP->MIXS, 0, sizeof( DSP->MIXS ) ); @@ -301,4 +407,5 @@ static void SCSPDSP_Start( struct _SCSPDSP *DSP ) break; } DSP->LastStep = i + 1; + DSP->Dirty = 1; } diff --git a/src/vidhrdw/model2_vidhrdw.c b/src/vidhrdw/model2_vidhrdw.c index 90925e91..64ed6abc 100644 --- a/src/vidhrdw/model2_vidhrdw.c +++ b/src/vidhrdw/model2_vidhrdw.c @@ -2285,6 +2285,8 @@ void model2_geo_parse( void ) /* drawn pixels carry an opaque marker in the top byte (the alpha of rgb_t in MAME), so a black pixel (dark shadows) is not taken as transparent */ #define M2_PIXEL_OPAQUE 0xff000000 +/* a pixel is kept as the 15-bit colour of the bitmap, from 8-bit components */ +#define M2_PIXEL( r, g, b ) ( M2_PIXEL_OPAQUE | ( ( (r) >> 3 ) << 10 ) | ( ( (g) >> 3 ) << 5 ) | ( (b) >> 3 ) ) /* the 3D frame. A drawn pixel is never 0 (M2_PIXEL_OPAQUE), so the buffer is its own fill map: polygons are drawn front to back and the first one @@ -2298,8 +2300,11 @@ static int m_dirty_minx, m_dirty_maxx, m_dirty_miny, m_dirty_maxy; /* empty: min typedef struct { const UINT32 *sheet; + const UINT8 *dsheet; /* the same sheet one byte per texel (model2_texdec0/1) */ UINT32 width, height; /* in texels, powers of two */ UINT32 x, y; /* position in the texture sheet */ + int inside; /* the whole level is inside the sheet */ + const UINT8 *dbase; /* inside, at an even x and y: its texel (0, 0) in dsheet */ } m2_tex_level; typedef struct @@ -2318,9 +2323,39 @@ typedef struct m2_tex_level level[ 16 ]; /* 0: the microtexture, 1 + n: mipmap level n */ } m2_poly_extra_data; +/* the texel fetch and the textured span are inlined in the opaque and the + translucent spans */ +#if defined(__GNUC__) +#define M2_ALWAYS_INLINE __attribute__((always_inline)) +#else +#define M2_ALWAYS_INLINE +#endif + +/* two neighbouring texels of a translucent texture, 4 bits each (index: + first << 4 | second), as the filtering takes them: the alpha component + (0x80 when not transparent, value 15) packed into the upper 16 bits, + and a transparent texel taking the luma of the other one, the first + one done first */ +static UINT32 m2_tex_pair[ 256 ][ 2 ]; + +static void m2_tex_pair_init( void ) +{ + int i; + for( i = 0; i < 256; i++ ) + { + UINT32 a = ( i >> 4 ) << 4, b = ( i & 15 ) << 4; + if( a != 0xf0 ) a |= 0x00800000; + if( b != 0xf0 ) b |= 0x00800000; + if( a == 0x000000f0 ) a = b & 0xff; + if( b == 0x000000f0 ) b = a & 0xff; + m2_tex_pair[ i ][ 0 ] = a; + m2_tex_pair[ i ][ 1 ] = b; + } +} + #define LERP( x, y, a ) ( ( (x) + ( ( ( (y) - (x) ) * (a) ) >> 8 ) ) & 0x00ff00ff ) -static UINT32 fetch_bilinear_texel( const m2_poly_extra_data *object, int translucent, INT32 miplevel, INT32 u, INT32 v ) +static INLINE M2_ALWAYS_INLINE UINT32 fetch_bilinear_texel( const m2_poly_extra_data *object, int translucent, INT32 miplevel, INT32 u, INT32 v ) { UINT32 tex_wrap_x = object->texwrapx; UINT32 tex_wrap_y = object->texwrapy; @@ -2378,6 +2413,32 @@ static UINT32 fetch_bilinear_texel( const m2_poly_extra_data *object, int transl v1 = v0, v0--, vfrac = 0x100; } + /* the four texels from the sheet taken apart (model2_tex_decode), when + none of them is past the sheet: the columns with the parity of the + texture coordinate, as the word layout below */ + if( level->dbase ) + { + /* at an even position the columns and rows are in order */ + const UINT8 *r0 = level->dbase + v0 * 2048; + const UINT8 *r1 = level->dbase + v1 * 2048; + tex00 = r0[ u0 ] << 4; + tex01 = r0[ u1 ] << 4; + tex10 = r1[ u0 ] << 4; + tex11 = r1[ u1 ] << 4; + } + else if( level->inside || ( tex_x + u1 < 2048 && tex_x + u0 < 2048 && tex_y + v0 < 1024 && tex_y + v1 < 1024 ) ) + { + const UINT8 *d = level->dsheet; + UINT32 xc0 = ( ( tex_x + u0 ) & ~1 ) | ( u0 & 1 ); + UINT32 xc1 = ( ( tex_x + u1 ) & ~1 ) | ( u1 & 1 ); + UINT32 yr0 = ( ( ( tex_y + v0 ) & ~1 ) | ( v0 & 1 ) ) * 2048; + UINT32 yr1 = ( ( ( tex_y + v1 ) & ~1 ) | ( v1 & 1 ) ) * 2048; + tex00 = d[ yr0 + xc0 ] << 4; + tex01 = d[ yr0 + xc1 ] << 4; + tex10 = d[ yr1 + xc0 ] << 4; + tex11 = d[ yr1 + xc1 ] << 4; + } + else /* the four 4-bit texels. Texture sheets are mapped as 2048x1024 but stored in RAM as 1024x2048: past column 1024 a texel is in the other half of the rows. A 32-bit word holds two 2x2 blocks: bit 1 of the @@ -2409,17 +2470,16 @@ static UINT32 fetch_bilinear_texel( const m2_poly_extra_data *object, int transl if( ( tex00 & tex01 & tex10 & tex11 ) == 0xf0 ) return 0x000000f0; - /* pack the alpha components into the upper 16 bits */ - if( tex00 != 0xf0 ) tex00 |= 0x00800000; - if( tex01 != 0xf0 ) tex01 |= 0x00800000; - if( tex10 != 0xf0 ) tex10 |= 0x00800000; - if( tex11 != 0xf0 ) tex11 |= 0x00800000; - - /* a transparent texel takes the luma of the neighbouring texel */ - if( tex00 == 0x000000f0 ) tex00 = tex01 & 0xff; - if( tex01 == 0x000000f0 ) tex01 = tex00 & 0xff; - if( tex10 == 0x000000f0 ) tex10 = tex11 & 0xff; - if( tex11 == 0x000000f0 ) tex11 = tex10 & 0xff; + /* the alpha components packed into the upper 16 bits, a transparent + texel taking the luma of its neighbour: m2_tex_pair, per pair */ + { + const UINT32 *q0 = m2_tex_pair[ tex00 | ( tex01 >> 4 ) ]; + const UINT32 *q1 = m2_tex_pair[ tex10 | ( tex11 >> 4 ) ]; + tex00 = q0[ 0 ]; + tex01 = q0[ 1 ]; + tex10 = q1[ 0 ]; + tex11 = q1[ 1 ]; + } } tex0x = LERP( tex00, tex01, ufrac ); @@ -2490,7 +2550,7 @@ static void draw_scanline_solid( int scanline, int startx, int stopx, const m2_p tr = model2_gamma_table[ colortable_r[ luma ] & 0xff ]; tg = model2_gamma_table[ colortable_g[ luma ] & 0xff ]; tb = model2_gamma_table[ colortable_b[ luma ] & 0xff ]; - color = M2_PIXEL_OPAQUE | ( tr << 16 ) | ( tg << 8 ) | tb; + color = M2_PIXEL( tr, tg, tb ); x = startx; dx = object->checker ? 2 : 1; @@ -2504,7 +2564,13 @@ static void draw_scanline_solid( int scanline, int startx, int stopx, const m2_p } } -static void draw_scanline_tex( int scanline, int startx, int stopx, float ooz, float uoz, float voz, +/* the pixels of the texels of the last colours drawn (0: not worked out + yet; a pixel always has M2_PIXEL_OPAQUE). Cleared at every frame, since + the luma RAM, the colour tables and the gamma can change between frames */ +static UINT32 m_texcolor[ 128 ]; +static UINT32 m_texcolor_key[ 3 ]; + +static INLINE M2_ALWAYS_INLINE void draw_scanline_tex( int scanline, int startx, int stopx, float ooz, float uoz, float voz, float dooz, float duoz, float dvoz, const m2_poly_extra_data *object, int translucent ) { UINT32 *p = &m_destmap[ scanline * DEST_W ]; @@ -2515,9 +2581,18 @@ static void draw_scanline_tex( int scanline, int startx, int stopx, float ooz, f UINT32 lumabase = object->lumabase; INT32 max_level = object->max_level; UINT32 obj_luma = object->luma; + INT32 texlod = object->texlod; + int utex = object->utex, utexminlod = object->utexminlod; int x, dx; colorbase = model2_palram[ ( colorbase + 0x1000 ) & 0x1fff ] & 0x7fff; + if( colorbase != m_texcolor_key[ 0 ] || lumabase != m_texcolor_key[ 1 ] || obj_luma != m_texcolor_key[ 2 ] ) + { + memset( m_texcolor, 0, sizeof( m_texcolor ) ); + m_texcolor_key[ 0 ] = colorbase; + m_texcolor_key[ 1 ] = lumabase; + m_texcolor_key[ 2 ] = obj_luma; + } colortable_r += ( ( colorbase >> 0 ) & 0x1f ) << 8; colortable_g += ( ( colorbase >> 5 ) & 0x1f ) << 8; colortable_b += ( ( colorbase >> 10 ) & 0x1f ) << 8; @@ -2550,7 +2625,7 @@ static void draw_scanline_tex( int scanline, int startx, int stopx, float ooz, f continue; z = 1.0f / ooz; - mml = -object->texlod + fast_log2( z ); + mml = -texlod + fast_log2( z ); level = mml >> 7; if( level < 0 ) level = 0; if( level > max_level ) level = max_level; @@ -2562,17 +2637,23 @@ static void draw_scanline_tex( int scanline, int startx, int stopx, float ooz, f if( mml > 0 && level < max_level ) { - UINT32 t2 = fetch_bilinear_texel( object, translucent, level + 1, u, v ); + UINT32 t2; INT32 frac = ( mml & 127 ) << 1; + /* translucent, four transparent texels and less than half of the + next level: under 50% whatever that one gives (its alpha is at + most 0x80), discarded below */ + if( translucent && t == 0x000000f0 && frac < 128 ) + continue; + t2 = fetch_bilinear_texel( object, translucent, level + 1, u, v ); t = LERP( t, t2, frac ); } - else if( object->utex && mml < 0 && ( !translucent || t >= 0x00010000 ) ) + else if( utex && mml < 0 && ( !translucent || t >= 0x00010000 ) ) { /* (with no alpha, a translucent texel stays under 50% after this blend, and is discarded below) */ /* microtexture; blend up to almost 50% */ UINT32 t2 = fetch_bilinear_texel( object, translucent, -1, u, v ); - INT32 frac = -mml >> object->utexminlod; + INT32 frac = -mml >> utexminlod; if( frac > 127 ) frac = 127; t = LERP( t, t2, frac ); } @@ -2585,19 +2666,41 @@ static void draw_scanline_tex( int scanline, int startx, int stopx, float ooz, f t &= 0xff; } - /* 8 bits of filtered texel, 128 entries in the translator map */ - luma = (UINT8)( ( (UINT32)model2_lumaram[ ( lumabase + ( t >> 1 ) ) & 0x7fff ] * obj_luma ) >> 8 ); - if( luma > 0x3f ) - luma = 0x3f; + /* 8 bits of filtered texel, 128 entries in the translator map; the + pixel of each entry is worked out once for the polygon's colours */ + { + UINT32 c = m_texcolor[ t >> 1 ]; + if( !c ) + { + luma = (UINT8)( ( (UINT32)model2_lumaram[ ( lumabase + ( t >> 1 ) ) & 0x7fff ] * obj_luma ) >> 8 ); + if( luma > 0x3f ) + luma = 0x3f; - tr = model2_gamma_table[ colortable_r[ luma ] & 0xff ]; - tg = model2_gamma_table[ colortable_g[ luma ] & 0xff ]; - tb = model2_gamma_table[ colortable_b[ luma ] & 0xff ]; + tr = model2_gamma_table[ colortable_r[ luma ] & 0xff ]; + tg = model2_gamma_table[ colortable_g[ luma ] & 0xff ]; + tb = model2_gamma_table[ colortable_b[ luma ] & 0xff ]; - p[ x ] = M2_PIXEL_OPAQUE | ( tr << 16 ) | ( tg << 8 ) | tb; + c = M2_PIXEL( tr, tg, tb ); + m_texcolor[ t >> 1 ] = c; + } + p[ x ] = c; + } } } +/* the opaque and the translucent spans, each with the texel fetches inlined */ +static void draw_scanline_tex_opaque( int scanline, int startx, int stopx, float ooz, float uoz, float voz, + float dooz, float duoz, float dvoz, const m2_poly_extra_data *object ) +{ + draw_scanline_tex( scanline, startx, stopx, ooz, uoz, voz, dooz, duoz, dvoz, object, 0 ); +} + +static void draw_scanline_tex_trans( int scanline, int startx, int stopx, float ooz, float uoz, float voz, + float dooz, float duoz, float dvoz, const m2_poly_extra_data *object ) +{ + draw_scanline_tex( scanline, startx, stopx, ooz, uoz, voz, dooz, duoz, dvoz, object, 1 ); +} + /* scanline rasterization of a convex polygon, pixel centres at +0.5 */ static void rasterize_polygon( const poly_vertex *v, int n, int minx, int maxx, int miny, int maxy, const m2_poly_extra_data *extra, int textured, int translucent ) @@ -2680,9 +2783,9 @@ static void rasterize_polygon( const poly_vertex *v, int n, int minx, int maxx, if( textured ) { float off = ( startx + 0.5f ) - xl; - draw_scanline_tex( y, startx, stopx, + ( translucent ? draw_scanline_tex_trans : draw_scanline_tex_opaque )( y, startx, stopx, pl[ 0 ] + dpdx[ 0 ] * off, pl[ 1 ] + dpdx[ 1 ] * off, pl[ 2 ] + dpdx[ 2 ] * off, - dpdx[ 0 ], dpdx[ 1 ], dpdx[ 2 ], extra, translucent ); + dpdx[ 0 ], dpdx[ 1 ], dpdx[ 2 ], extra ); } else draw_scanline_solid( y, startx, stopx, extra, translucent ); @@ -2743,18 +2846,24 @@ static void model2_3d_render( polygon *poly, const struct rectangle *cliprect ) int level; extra.max_level = 30 - count_leading_zeros32( minwh ); extra.level[ 0 ].sheet = extra.texsheet[ 1 ]; + extra.level[ 0 ].dsheet = ( extra.texsheet[ 1 ] == model2_textureram0 ) ? model2_texdec0 : model2_texdec1; extra.level[ 0 ].width = 128; extra.level[ 0 ].height = 128; extra.level[ 0 ].x = extra.utexx; extra.level[ 0 ].y = extra.utexy; + extra.level[ 0 ].inside = 1; + extra.level[ 0 ].dbase = extra.level[ 0 ].dsheet + extra.utexy * 2048 + extra.utexx; for( level = 0; level <= extra.max_level; level++ ) { m2_tex_level *l = &extra.level[ level + 1 ]; l->sheet = extra.texsheet[ level & 1 ]; + l->dsheet = ( l->sheet == model2_textureram0 ) ? model2_texdec0 : model2_texdec1; l->width = extra.texwidth >> level; l->height = extra.texheight >> level; l->x = ( ( extra.texx - 2048 ) >> level ) & 2047; l->y = ( ( extra.texy - 1024 ) >> level ) & 1023; + l->inside = l->x + l->width <= 2048 && l->y + l->height <= 1024; + l->dbase = ( l->inside && !( ( l->x | l->y ) & 1 ) ) ? l->dsheet + l->y * 2048 + l->x : NULL; } } @@ -2791,11 +2900,14 @@ static void composite_3d( struct mame_bitmap *bitmap, const struct rectangle *cl { UINT16 *dst = (UINT16 *)bitmap->line[ y ]; const UINT32 *src = &m_destmap[ y * DEST_W ]; + const UINT8 *pri = (const UINT8 *)priority_bitmap->line[ y ]; for( x = minx; x <= maxx; x++ ) { UINT32 c = src[ x ]; - if( c ) - dst[ x ] = ( ( c >> 9 ) & 0x7c00 ) | ( ( c >> 6 ) & 0x03e0 ) | ( ( c >> 3 ) & 0x001f ); + /* not over a tile pixel in front of the polygons: the highest + bit of its priority value is odd (see VIDEO_UPDATE) */ + if( c && ( pri[ x ] & 0xaa ) <= ( pri[ x ] & 0x55 ) ) + dst[ x ] = (UINT16)c; } } } @@ -2822,6 +2934,7 @@ static void render_polygons( struct mame_bitmap *bitmap, const struct rectangle memset( &m_destmap[ y * DEST_W + m_dirty_minx ], 0, ( m_dirty_maxx - m_dirty_minx + 1 ) * sizeof( UINT32 ) ); m_dirty_minx = m_dirty_miny = DEST_W; m_dirty_maxx = m_dirty_maxy = -1; + memset( m_texcolor, 0, sizeof( m_texcolor ) ); for( window = raster->cur_window; window >= 0; window-- ) { @@ -2862,8 +2975,6 @@ READ32_HANDLER( model2_polygon_count_r ) } /* the tile layers, mixed (see VIDEO_UPDATE) */ -static struct mame_bitmap *m_tilemap; /* the tile layers, mixed */ -static UINT8 m_tile_front[ 256 ]; /* light gun crosshairs (Virtua Cop, Virtua Cop 2, The House of the Dead): the gun ports span the whole screen, as PORT_CROSSHAIR( X/Y, 1.0, 0.0 ) @@ -2921,23 +3032,11 @@ static void draw_gun_crosshairs( struct mame_bitmap *bitmap, const struct rectan VIDEO_START( model2 ) { - int i; + m2_tex_pair_init(); if( sys24_tile_vh_start( 0x3fff ) ) return 1; - m_tilemap = auto_bitmap_alloc( Machine->drv->screen_width, Machine->drv->screen_height ); - if( !m_tilemap ) - return 1; - /* priority bitmap value -> the winning tile pixel is in front of the polygons */ - for( i = 0; i < 256; i++ ) - { - int b = 7; - while( b > 0 && !( i & ( 1 << b ) ) ) - b--; - m_tile_front[ i ] = b & 1; - } - m_raster = auto_malloc( sizeof( raster_state ) ); m_geo = auto_malloc( sizeof( geo_state ) ); memset( m_raster, 0, sizeof( raster_state ) ); @@ -3006,25 +3105,13 @@ VIDEO_START( model2 ) A: on the Virtua Cop 2 stage select the city map (B, priority set) hid "SHOOT TO SELECT" (A). - The tiles are drawn back to front into m_tilemap, each layer and - priority setting its own bit in the priority bitmap: bit 2*depth+prio, - with depth 0 for the back layer. The highest bit set gives the winning - pixel and its priority. + The tiles are drawn back to front straight into the bitmap, each + layer and priority setting its own bit in the priority bitmap: bit + 2*depth+prio, with depth 0 for the back layer. The highest bit set + gives the winning pixel and its priority: the polygons are then drawn + where it is even (behind them) or there is no tile pixel. A highest bit + odd is the same as the odd bits above the even ones. */ -static void copy_tiles( struct mame_bitmap *bitmap, const struct rectangle *cliprect, int front ) -{ - int x, y; - for( y = cliprect->min_y; y <= cliprect->max_y; y++ ) - { - UINT16 *dst = (UINT16 *)bitmap->line[ y ]; - const UINT16 *src = (const UINT16 *)m_tilemap->line[ y ]; - const UINT8 *pri = (const UINT8 *)priority_bitmap->line[ y ]; - for( x = cliprect->min_x; x <= cliprect->max_x; x++ ) - if( pri[ x ] && m_tile_front[ pri[ x ] ] == front ) - dst[ x ] = src[ x ]; - } -} - VIDEO_UPDATE( model2 ) { int layer; @@ -3039,13 +3126,12 @@ VIDEO_UPDATE( model2 ) for( layer = 3; layer >= 0; layer-- ) { int depth = 3 - layer; - sys24_tile_draw( m_tilemap, cliprect, layer << 1, depth * 2, 0 ); - sys24_tile_draw( m_tilemap, cliprect, ( layer << 1 ) | 1, depth * 2 + 1, 0 ); + sys24_tile_draw( bitmap, cliprect, layer << 1, depth * 2, 0 ); + sys24_tile_draw( bitmap, cliprect, ( layer << 1 ) | 1, depth * 2 + 1, 0 ); } - copy_tiles( bitmap, cliprect, 0 ); + /* the polygons go over the tile pixels behind them only */ render_polygons( bitmap, cliprect ); - copy_tiles( bitmap, cliprect, 1 ); draw_gun_crosshairs( bitmap, cliprect ); } diff --git a/src/vidhrdw/segaic24.c b/src/vidhrdw/segaic24.c index 0d757795..95734c05 100644 --- a/src/vidhrdw/segaic24.c +++ b/src/vidhrdw/segaic24.c @@ -368,6 +368,25 @@ static void sys24_tile_draw_rect(struct mame_bitmap *bm, struct mame_bitmap *tm, find the topmost tile layer of each pixel. */ +/* eight bytes of the transparency bitmap at once: nonzero when one of them is + the byte repeated in every lane of 'pat' (the usual zero byte test) */ +static INLINE int sys24_trans8_has(const UINT8 *p, UINT64 pat) +{ + const UINT64 ones = ((UINT64)0x01010101 << 32) | 0x01010101; + UINT64 w; + memcpy(&w, p, 8); + w ^= pat; + return ((w - ones) & ~w & (ones << 7)) != 0; +} + +/* eight bytes of the transparency bitmap all the byte of 'pat' */ +static INLINE int sys24_trans8_all(const UINT8 *p, UINT64 pat) +{ + UINT64 w; + memcpy(&w, p, 8); + return w == pat; +} + static void sys24_tile_draw_rect_rgb(struct mame_bitmap *bm, struct mame_bitmap *tm, struct mame_bitmap *dm, const UINT16 *mask, UINT16 tpri, UINT8 lpri, int win, int sx, int sy, int xx1, int yy1, int xx2, int yy2) { @@ -377,8 +396,11 @@ static void sys24_tile_draw_rect_rgb(struct mame_bitmap *bm, struct mame_bitmap UINT16 *dest = dm->base; UINT8 *prib = priority_bitmap->base; pen_t *pens = Machine->pens; + UINT64 tpat; tpri |= TILE_FLAG_FG_OPAQUE; + /* tpri in every byte (a value over 0xff never matches: no group is skipped) */ + tpat = (((UINT64)0x01010101 << 32) | 0x01010101) * (tpri & 0xff); dest += yy1*dm->rowpixels + xx1; prib += yy1*priority_bitmap->rowpixels + xx1; @@ -410,14 +432,26 @@ static void sys24_tile_draw_rect_rgb(struct mame_bitmap *bm, struct mame_bitmap /* Fast paths for the 128-pixels without side clipping case */ if(!m) { - /* 1- 128 pixels from this layer */ + /* 1- 128 pixels from this layer, eight at a time: a group + with no pixel of this priority is skipped */ int x; - for(x=0; x<128; x++) { - if(*srct++ == tpri) - { *dst = pens[*src]; *pr |= lpri; } - src++; - dst++; - pr++; + for(x=0; x<128; x+=8) { + if(tpri > 0xff || sys24_trans8_has(srct, tpat)) { + int xx; + if(tpri <= 0xff && sys24_trans8_all(srct, tpat)) { + /* eight pixels of this priority */ + for(xx=0; xx<8; xx++) + { dst[xx] = pens[src[xx]]; pr[xx] |= lpri; } + } else { + for(xx=0; xx<8; xx++) + if(srct[xx] == tpri) + { dst[xx] = pens[src[xx]]; pr[xx] |= lpri; } + } + } + src += 8; + srct += 8; + dst += 8; + pr += 8; } } else if(m == 0xffff) { @@ -431,11 +465,17 @@ static void sys24_tile_draw_rect_rgb(struct mame_bitmap *bm, struct mame_bitmap /* 3- 128 pixels from both layers */ int x; for(x=0; x<128; x+=8) { - if(!(m & 0x8000)) { + if(!(m & 0x8000) && (tpri > 0xff || sys24_trans8_has(srct, tpat))) { int xx; - for(xx=0; xx<8; xx++) - if(srct[xx] == tpri) - { dst[xx] = pens[src[xx]]; pr[xx] |= lpri; } + if(tpri <= 0xff && sys24_trans8_all(srct, tpat)) { + /* eight pixels of this priority */ + for(xx=0; xx<8; xx++) + { dst[xx] = pens[src[xx]]; pr[xx] |= lpri; } + } else { + for(xx=0; xx<8; xx++) + if(srct[xx] == tpri) + { dst[xx] = pens[src[xx]]; pr[xx] |= lpri; } + } } src += 8; srct += 8; @@ -448,7 +488,30 @@ static void sys24_tile_draw_rect_rgb(struct mame_bitmap *bm, struct mame_bitmap /* Clipped path */ int llx1 = llx >= 128 ? 128 : llx; - if(!m) { + if(!m && !cur_x && !(llx1 & 7)) { + /* 1- the last pixels of the line from this layer, a + whole number of groups of eight: as the fast path */ + int x; + for(x=0; x 0xff || sys24_trans8_has(srct, tpat)) { + int xx; + if(tpri <= 0xff && sys24_trans8_all(srct, tpat)) { + /* eight pixels of this priority */ + for(xx=0; xx<8; xx++) + { dst[xx] = pens[src[xx]]; pr[xx] |= lpri; } + } else { + for(xx=0; xx<8; xx++) + if(srct[xx] == tpri) + { dst[xx] = pens[src[xx]]; pr[xx] |= lpri; } + } + } + src += 8; + srct += 8; + dst += 8; + pr += 8; + } + + } else if(!m) { /* 1- 128 pixels from this layer */ int x; for(x = cur_x; x