diff --git a/include/rdpq_macros.h b/include/rdpq_macros.h index a1ee1be99..6b6c7a9b7 100644 --- a/include/rdpq_macros.h +++ b/include/rdpq_macros.h @@ -513,6 +513,7 @@ typedef uint32_t rdpq_blender_t; ///@{ #define SOMX_NUMLODS_MASK ((cast64(7))<<59) ///< Rdpq extension: number of LODs #define SOMX_NUMLODS_SHIFT 59 ///< Rdpq extension: number of LODs shift +#define SOMX_FOG ((cast64(1))<<58) ///< RDPQ special state: fogging is enabled #define SOM_ATOMIC_PRIM ((cast64(1))<<55) ///< Atomic: serialize command execution @@ -563,10 +564,12 @@ typedef uint32_t rdpq_blender_t; #define SOM_ALPHADITHER_MASK ((cast64(3))<<36) ///< Alpha Dithering mask #define SOM_ALPHADITHER_SHIFT 36 ///< Alpha Dithering mask shift -#define SOMX_FOG ((cast64(1))<<32) ///< RDPQ special state: fogging is enabled -#define SOMX_UPDATE_FREEZE ((cast64(1))<<33) ///< RDPQ special state: render mode update is frozen (see #rdpq_mode_begin) -#define SOMX_AA_REDUCED ((cast64(1))<<34) ///< RDPQ special state: reduced antialiasing is enabled -#define SOMX_LOD_INTERPOLATE ((cast64(1))<<35) ///< RDPQ special state: mimap interpolation (aka trilinear) requested +#define SOMX_LOD_INTERPOLATE ((cast64(1))<<32) ///< RDPQ special state: mimap interpolation (aka trilinear) requested +#define SOMX_LOD_INTERPOLATE_SHQ ((cast64(1))<<33) ///< RDPQ special state: mimap interpolation for SHC texture format +#define SOMX_LOD_INTERP_MASK ((cast64(3))<<32) ///< RDPQ special state: mask for LOD interpolation formulas +#define SOMX_LOD_INTERP_SHIFT 32 ///< RDPQ special state: shift for LOD interpolation formulas +#define SOMX_AA_REDUCED ((cast64(1))<<34) ///< RDPQ special state: reduced antialiasing is enabled +#define SOMX_UPDATE_FREEZE ((cast64(1))<<35) ///< RDPQ special state: render mode update is frozen (see #rdpq_mode_begin) #define SOM_BLEND0_MASK (cast64(0xCCCC0000) | SOM_BLENDING | SOM_READ_ENABLE | SOMX_BLEND_2PASS) ///< Blender: mask of settings related to pass 0 #define SOM_BLEND1_MASK (cast64(0x33330000) | SOM_BLENDING | SOM_READ_ENABLE | SOMX_BLEND_2PASS) ///< Blender: mask of settings related to pass 1 diff --git a/include/rdpq_mode.h b/include/rdpq_mode.h index 39c5afad2..64d3c9cf2 100644 --- a/include/rdpq_mode.h +++ b/include/rdpq_mode.h @@ -248,6 +248,7 @@ typedef enum rdpq_mipmap_s { MIPMAP_INTERPOLATE = (SOM_TEXTURE_LOD | SOMX_LOD_INTERPOLATE) >> 32, ///< Interpolate between the two nearest mipmap levels (also known as "trilinear") MIPMAP_INTERPOLATE_SHARPEN = (SOM_TEXTURE_LOD | SOMX_LOD_INTERPOLATE | SOM_TEXTURE_SHARPEN) >> 32, ///< Interpolate between the two nearest mipmap levels (also known as "trilinear") with sharpening enabled MIPMAP_INTERPOLATE_DETAIL = (SOM_TEXTURE_LOD | SOMX_LOD_INTERPOLATE | SOM_TEXTURE_DETAIL) >> 32, ///< Interpolate between the two nearest mipmap levels (also known as "trilinear") with detail texture enabled + MIPMAP_INTERPOLATE_SHQ = (SOM_TEXTURE_LOD | SOMX_LOD_INTERPOLATE_SHQ) >> 32, ///< Special mipmap mode that must be used for SHC textures } rdpq_mipmap_t; /** diff --git a/include/rsp_rdpq.inc b/include/rsp_rdpq.inc index 7c56b27bd..acdd1d62f 100644 --- a/include/rsp_rdpq.inc +++ b/include/rsp_rdpq.inc @@ -218,7 +218,8 @@ AA_BLEND_DEFAULT_FORMULA: .word RDPQ_BLENDER((IN_RGB, IN_ALPHA, MEMORY_RGB, MEMORY_CVG)) # Standard AA .word RDPQ_BLENDER((IN_RGB, IN_ALPHA, MEMORY_RGB, MEMORY_CVG)) & ~SOM_READ_ENABLE # Reduced AA -#define RDPQ_COMB_MIPMAP2 RDPQ_COMBINER2((TEX1, TEX0, LOD_FRAC, TEX0), (TEX1, TEX0, LOD_FRAC, TEX0), (0,0,0,0), (0,0,0,0)) +#define RDPQ_COMB_LOD_INTERP RDPQ_COMBINER2((TEX1, TEX0, LOD_FRAC, TEX0), (TEX1, TEX0, LOD_FRAC, TEX0), (0,0,0,0), (0,0,0,0)) +#define RDPQ_COMB_LOD_SHQ RDPQ_COMBINER2((TEX1, TEX0, K5, 0 ), (0, 0, 0, TEX1), (0,0,0,0), (0,0,0,0)) #define RDPQ_COMB_SHADE_FOG RDPQ_COMBINER1((0,0,0,SHADE), (0,0,0,1)) #define RDPQ_COMB_TEX_SHADE_FOG RDPQ_COMBINER1((TEX0,0,SHADE,0), (0,0,0,TEX0)) @@ -228,7 +229,9 @@ COMBINER_SHADE_FOG: .quad RDPQ_COMB_SHADE_FOG COMBINER_TEX_SHADE: .quad RDPQ_COMBINER_TEX_SHADE COMBINER_TEX_SHADE_FOG: .quad RDPQ_COMB_TEX_SHADE_FOG -COMBINER_MIPMAP2: .quad (RDPQ_COMB_MIPMAP2 & RDPQ_COMB0_MASK) | RDPQ_COMBINER_2PASS +COMBINER_MIPMAPS: + .quad (RDPQ_COMB_LOD_INTERP & RDPQ_COMB0_MASK) | RDPQ_COMBINER_2PASS + .quad (RDPQ_COMB_LOD_SHQ & RDPQ_COMB0_MASK) | RDPQ_COMBINER_2PASS .section .bss.rdpq_mode_api @@ -351,7 +354,8 @@ RDPQ_UpdateRenderMode: calc_comb_1cyc: # Check if fogging is active - andi t0, som_hi, SOMX_FOG >> 32 + li t1, SOMX_FOG >> 32 + and t0, som_hi, t1 beqz t0, check_mipmap_interp # Create a copy of comb_hi without the cmd ID in the top MSB. @@ -383,10 +387,11 @@ fog_change: lw comb_lo, 4(s0) check_mipmap_interp: - and t0, som_hi, SOMX_LOD_INTERPOLATE >> 32 - beqz t0, store_comb_1cyc + andi t2, som_hi, SOMX_LOD_INTERP_MASK >> 32 + beqz t2, store_comb_1cyc + sll t2, 3 - (SOMX_LOD_INTERP_SHIFT - 32) # Prepare offset for the current mipmap interpolation mode - # Interpolated mipmapping is active. We want to add RDPQ_COMB_MIPMAP as step0 + # Interpolated mipmapping is active. We want to add a special combiner step as step0 # and use only step 1 of the incoming formula. Unfortunately, this # also means that all TEX0 slots must be converted into COMBINED slots. # We do this by using the mask already loaded in a2/a3 @@ -397,8 +402,8 @@ check_mipmap_interp: # Since this combiner now requires two-cycle mode, we can simply store in the # 2-cycle mode slot. No need to touch the 1-cycle mode slot as it will not # be used anyway. - lw t0, %lo(COMBINER_MIPMAP2) + 0 - lw t1, %lo(COMBINER_MIPMAP2) + 4 + lw t0, %lo(COMBINER_MIPMAPS) - 8(t2) + lw t1, %lo(COMBINER_MIPMAPS) - 4(t2) or comb_hi, t0 j store_comb_2cyc or comb_lo, t1 diff --git a/include/sprite.h b/include/sprite.h index 52f1e05af..6adc50f68 100644 --- a/include/sprite.h +++ b/include/sprite.h @@ -268,6 +268,16 @@ int sprite_get_lod_count(sprite_t *sprite); */ bool sprite_fits_tmem(sprite_t *sprite); +/** + * @brief Return true if the sprite is in SHQ format + * + * This is a special sprite made of two mipmaps (one I4 and one RGBA16) + * that must be displayed using subtractive blending. + * + * @param sprite The sprite to access + * @return True if the sprite is in SHQ format, false otherwise + */ +bool sprite_is_shq(sprite_t *sprite); #ifdef __cplusplus } diff --git a/src/rdpq/rdpq_sprite.c b/src/rdpq/rdpq_sprite.c index 00298e9fc..4f1e69979 100644 --- a/src/rdpq/rdpq_sprite.c +++ b/src/rdpq/rdpq_sprite.c @@ -51,6 +51,7 @@ int __rdpq_sprite_upload(rdpq_tile_t tile, sprite_t *sprite, const rdpq_texparms sprite_detail_t detail; rdpq_texparms_t detailtexparms = {0}; surface_t detailsurf = sprite_get_detail_pixels(sprite, &detail, &detailtexparms); bool use_detail = detailsurf.buffer != NULL; + bool is_shq = sprite_is_shq(sprite); rdpq_tex_multi_begin(); @@ -112,7 +113,11 @@ int __rdpq_sprite_upload(rdpq_tile_t tile, sprite_t *sprite, const rdpq_texparms if (__builtin_expect(set_mode, 1)) { // Enable/disable mipmapping - if(use_detail) rdpq_mode_mipmap(MIPMAP_INTERPOLATE_DETAIL, num_mipmaps+1); + if(is_shq) { + rdpq_mode_mipmap(MIPMAP_INTERPOLATE_SHQ, num_mipmaps+1); + rdpq_set_yuv_parms(0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF); + } + else if(use_detail) rdpq_mode_mipmap(MIPMAP_INTERPOLATE_DETAIL, num_mipmaps+1); else if (num_mipmaps) rdpq_mode_mipmap(MIPMAP_INTERPOLATE, num_mipmaps); else rdpq_mode_mipmap(MIPMAP_NONE, 0); } diff --git a/src/sprite.c b/src/sprite.c index 4ed99a89f..e29c39016 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -224,4 +224,12 @@ bool sprite_fits_tmem(sprite_t *sprite) return (sx->flags & SPRITE_FLAG_FITS_TMEM) != 0; } +bool sprite_is_shq(sprite_t *sprite) +{ + sprite_ext_t *sx = __sprite_ext(sprite); + if (!sx) + return false; + return (sx->flags & SPRITE_FLAG_SHQ) != 0; +} + extern inline tex_format_t sprite_get_format(sprite_t *sprite); diff --git a/src/sprite_internal.h b/src/sprite_internal.h index 4115c6aa6..e1dabb9e6 100644 --- a/src/sprite_internal.h +++ b/src/sprite_internal.h @@ -8,6 +8,7 @@ #define SPRITE_FLAG_HAS_TEXPARMS 0x0008 ///< Sprite contains texture parameters #define SPRITE_FLAG_HAS_DETAIL 0x0010 ///< Sprite contains detail texture #define SPRITE_FLAG_FITS_TMEM 0x0020 ///< Set if the sprite does fit TMEM without splitting +#define SPRITE_FLAG_SHQ 0x0040 ///< Sprite is in special SHQ format (2 mipmap levels with subtractive blending) /** * @brief Internal structure used as additional sprite header diff --git a/tests/test_rdpq.c b/tests/test_rdpq.c index fe26152ae..a8e40d62a 100644 --- a/tests/test_rdpq.c +++ b/tests/test_rdpq.c @@ -52,6 +52,15 @@ uint64_t debug_rdp_stream_last_cc(void) { return rdp_stream[rdp_stream_ctx.last_cc]; } +const char* debug_rdp_stream_last_cc_disasm(void) { + uint64_t cmds[1] = { debug_rdp_stream_last_cc() }; + static char buf[256]; + FILE *out = fmemopen(buf, sizeof(buf), "w"); + rdpq_debug_disasm(cmds, out); + fclose(out); + return buf; +} + uint32_t debug_rdp_stream_count_cmd(uint32_t cmd_id) { uint32_t count = 0; for (int i=0;iimages[i].height); w_lodpos[i-1] = w32_placeholder(out); // placeholder for position of LOD } - uint16_t flags = 0; + uint16_t flags = spr->out_flags; assert(numlods <= 7); // 3 bits flags |= numlods; if (spr->texparms.defined) flags |= 0x8; @@ -1530,6 +1531,7 @@ int convert(const char *infn, const char *outfn, const parms_t *pm) { // Compute mipmaps for IHQ mipmap_algo = MIPMAP_ALGO_BOX; } else if (spr.images[0].fmt == FMT_SHQ) { + spr.out_flags |= 0x40; if (!spritemaker_convert_shq(&spr)) goto error; // Compute mipmaps for IHQ