diff --git a/CMakeLists.txt b/CMakeLists.txt index f6d33e3..3592c88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,6 +131,7 @@ add_object_library_macros(GS_CORE_OBJS ee/gs/src/gsCore.c gsKit_set_clamp gsKit_set_primalpha gsKit_set_texfilter + gsKit_set_texclut gsKit_set_dither_matrix gsKit_set_dither gsKit_set_drawfield @@ -351,6 +352,7 @@ if(NOT SKIP_BUILD_EXAMPLES) bigtex coverflow clut + clutcsm cube fb fhdbg diff --git a/ee/gs/include/gsCore.h b/ee/gs/include/gsCore.h index 4bdba3b..972d600 100644 --- a/ee/gs/include/gsCore.h +++ b/ee/gs/include/gsCore.h @@ -68,6 +68,11 @@ /// Use bilinear filter on texture #define GS_FILTER_LINEAR 0x01 +/// Use clut storage mode CSM1 +#define GS_CLUT_STORAGE_CSM1 0x00 +/// Use clut storage mode CSM2 +#define GS_CLUT_STORAGE_CSM2 0x01 + /// Basic X/Y/Z Vertex Structure struct gsVertex { @@ -209,6 +214,9 @@ void gsKit_set_primalpha(GSGLOBAL *gsGlobal, u64 AlphaMode, u8 PerPixel); /// Sets the Texture Filtering Parameters void gsKit_set_texfilter(GSGLOBAL *gsGlobal, u8 FilterMode); +/// Sets the CLUT position specfications +void gsKit_set_texclut(GSGLOBAL *gsGlobal, gs_texclut texClut); + /// Sets the Dither Matrix Setting void gsKit_set_dither_matrix(GSGLOBAL *gsGlobal); diff --git a/ee/gs/include/gsInit.h b/ee/gs/include/gsInit.h index 8562067..3588764 100644 --- a/ee/gs/include/gsInit.h +++ b/ee/gs/include/gsInit.h @@ -959,6 +959,7 @@ struct gsTexture u32 Vram; ///< GS VRAM Memory Pointer u32 VramClut; ///< GS VRAM CLUT Memory Pointer u32 Filter; ///< NEAREST or LINEAR + u8 ClutStorageMode; ///< CLUT Storage Mode u8 Delayed; ///< Delay Texture Upload To VRAM }; typedef struct gsTexture GSTEXTURE; @@ -1039,6 +1040,25 @@ typedef union { }; } __attribute__((packed)) gs_stq; +typedef union { + u64 position; + struct { + u32 cbw : 6; // Bits 0-5 (6 bits) + u32 cou : 6; // Bits 6-11 (6 bits) + u32 cov : 10; // Bits 12-21 (10 bits) + u32 unused_bits: 10; // Bits 22-31 (10 bits) + u32 unused; // Remaining bits (64 - 22 = 42 bits) + } __attribute__((packed)); // Pack the structure to avoid padding +} __attribute__((packed)) gs_textclut_t; + +typedef union { + u128 texclut; + struct { + gs_textclut_t specification; + u64 tag; + }; +} __attribute__((packed)) gs_texclut; + /// gsKit Point Primitive Structure /// This structure holds all relevant data for any /// given point object, regardless of original format or type. diff --git a/ee/gs/include/gsInline.h b/ee/gs/include/gsInline.h index e065433..d2b4fb1 100644 --- a/ee/gs/include/gsInline.h +++ b/ee/gs/include/gsInline.h @@ -230,4 +230,16 @@ static inline gs_stq vertex_to_STQ(float s, float t) return res; } +static inline gs_texclut postion_to_TEXCLUT(u8 cbw, u8 cou, u8 cov) +{ + gs_texclut res; + + res.specification.cbw = cbw; + res.specification.cou = cou; + res.specification.cov = cov; + res.tag = GS_TEXCLUT; + + return res; +} + #endif /* __GSINLINE_H__ */ diff --git a/ee/gs/src/gsCore.c b/ee/gs/src/gsCore.c index cb43f5b..095eea4 100644 --- a/ee/gs/src/gsCore.c +++ b/ee/gs/src/gsCore.c @@ -411,6 +411,22 @@ void gsKit_set_texfilter(GSGLOBAL *gsGlobal, u8 FilterMode) } #endif +#if F_gsKit_set_texclut +void gsKit_set_texclut(GSGLOBAL *gsGlobal, gs_texclut texClut) +{ + u64 *p_data; + u64 *p_store; + + p_data = p_store = gsKit_heap_alloc(gsGlobal, 1, 16, GIF_AD); + + *p_data++ = GIF_TAG_AD(1); + *p_data++ = GIF_AD; + + memcpy(p_data, &texClut, sizeof(gs_texclut)); + p_data += 2; // Advance 2 u64, which is 16 bytes the gs_texclut struct size +} +#endif + #if F_gsKit_set_dither_matrix void gsKit_set_dither_matrix(GSGLOBAL *gsGlobal) { diff --git a/ee/gs/src/gsTexture.c b/ee/gs/src/gsTexture.c index 70c06f1..73ef218 100644 --- a/ee/gs/src/gsTexture.c +++ b/ee/gs/src/gsTexture.c @@ -505,7 +505,7 @@ void gsKit_prim_sprite_texture_3d(GSGLOBAL *gsGlobal, const GSTEXTURE *Texture, { *p_data++ = GS_SETREG_TEX0(Texture->Vram/256, Texture->TBW, Texture->PSM, tw, th, gsGlobal->PrimAlphaEnable, 0, - Texture->VramClut/256, Texture->ClutPSM, 0, 0, GS_CLUT_STOREMODE_LOAD); + Texture->VramClut/256, Texture->ClutPSM, Texture->ClutStorageMode, 0, GS_CLUT_STOREMODE_LOAD); } *p_data++ = GS_SETREG_PRIM( GS_PRIM_PRIM_SPRITE, 0, 1, gsGlobal->PrimFogEnable, @@ -720,7 +720,7 @@ void gskit_prim_list_sprite_texture_uv_3d(GSGLOBAL *gsGlobal, const GSTEXTURE *T { *p_data++ = GS_SETREG_TEX0(Texture->Vram/256, Texture->TBW, Texture->PSM, tw, th, gsGlobal->PrimAlphaEnable, 0, - Texture->VramClut/256, Texture->ClutPSM, 0, 0, GS_CLUT_STOREMODE_LOAD); + Texture->VramClut/256, Texture->ClutPSM, Texture->ClutStorageMode, 0, GS_CLUT_STOREMODE_LOAD); } *p_data++ = GS_TEX0_1 + gsGlobal->PrimContext; @@ -765,7 +765,7 @@ void gskit_prim_list_sprite_texture_uv_flat(GSGLOBAL *gsGlobal, const GSTEXTURE { *p_data++ = GS_SETREG_TEX0(Texture->Vram/256, Texture->TBW, Texture->PSM, tw, th, gsGlobal->PrimAlphaEnable, 0, - Texture->VramClut/256, Texture->ClutPSM, 0, 0, GS_CLUT_STOREMODE_LOAD); + Texture->VramClut/256, Texture->ClutPSM, Texture->ClutStorageMode, 0, GS_CLUT_STOREMODE_LOAD); } *p_data++ = GS_TEX0_1 + gsGlobal->PrimContext; @@ -810,7 +810,7 @@ void gskit_prim_list_sprite_texture_uv_flat_color(GSGLOBAL *gsGlobal, const GSTE { *p_data++ = GS_SETREG_TEX0(Texture->Vram/256, Texture->TBW, Texture->PSM, tw, th, gsGlobal->PrimAlphaEnable, 0, - Texture->VramClut/256, Texture->ClutPSM, 0, 0, GS_CLUT_STOREMODE_LOAD); + Texture->VramClut/256, Texture->ClutPSM, Texture->ClutStorageMode, 0, GS_CLUT_STOREMODE_LOAD); } *p_data++ = GS_TEX0_1 + gsGlobal->PrimContext; @@ -891,7 +891,7 @@ void gsKit_prim_triangle_texture_3d(GSGLOBAL *gsGlobal, GSTEXTURE *Texture, { *p_data++ = GS_SETREG_TEX0(Texture->Vram/256, Texture->TBW, Texture->PSM, tw, th, gsGlobal->PrimAlphaEnable, 0, - Texture->VramClut/256, Texture->ClutPSM, 0, 0, GS_CLUT_STOREMODE_LOAD); + Texture->VramClut/256, Texture->ClutPSM, Texture->ClutStorageMode, 0, GS_CLUT_STOREMODE_LOAD); } *p_data++ = GS_SETREG_PRIM( GS_PRIM_PRIM_TRIANGLE, 0, 1, gsGlobal->PrimFogEnable, @@ -975,7 +975,7 @@ void gsKit_prim_triangle_goraud_texture_3d(GSGLOBAL *gsGlobal, GSTEXTURE *Textur { *p_data++ = GS_SETREG_TEX0(Texture->Vram/256, Texture->TBW, Texture->PSM, tw, th, gsGlobal->PrimAlphaEnable, 0, - Texture->VramClut/256, Texture->ClutPSM, 0, 0, GS_CLUT_STOREMODE_LOAD); + Texture->VramClut/256, Texture->ClutPSM, Texture->ClutStorageMode, 0, GS_CLUT_STOREMODE_LOAD); } *p_data++ = GS_SETREG_PRIM( GS_PRIM_PRIM_TRIANGLE, 1, 1, gsGlobal->PrimFogEnable, @@ -1028,7 +1028,7 @@ void gsKit_prim_list_triangle_goraud_texture_uv_3d(GSGLOBAL *gsGlobal, GSTEXTURE { *p_data++ = GS_SETREG_TEX0(Texture->Vram/256, Texture->TBW, Texture->PSM, tw, th, gsGlobal->PrimAlphaEnable, 0, - Texture->VramClut/256, Texture->ClutPSM, 0, 0, GS_CLUT_STOREMODE_LOAD); + Texture->VramClut/256, Texture->ClutPSM, Texture->ClutStorageMode, 0, GS_CLUT_STOREMODE_LOAD); } *p_data++ = GS_TEX0_1 + gsGlobal->PrimContext; @@ -1073,7 +1073,7 @@ void gsKit_prim_list_triangle_goraud_texture_stq_3d(GSGLOBAL *gsGlobal, GSTEXTUR { *p_data++ = GS_SETREG_TEX0(Texture->Vram/256, Texture->TBW, Texture->PSM, tw, th, gsGlobal->PrimAlphaEnable, 0, - Texture->VramClut/256, Texture->ClutPSM, 0, 0, GS_CLUT_STOREMODE_LOAD); + Texture->VramClut/256, Texture->ClutPSM, Texture->ClutStorageMode, 0, GS_CLUT_STOREMODE_LOAD); } *p_data++ = GS_TEX0_1 + gsGlobal->PrimContext; @@ -1127,7 +1127,7 @@ void gsKit_prim_triangle_strip_texture(GSGLOBAL *gsGlobal, GSTEXTURE *Texture, { *p_data++ = GS_SETREG_TEX0(Texture->Vram/256, Texture->TBW, Texture->PSM, tw, th, gsGlobal->PrimAlphaEnable, 0, - Texture->VramClut/256, Texture->ClutPSM, 0, 0, GS_CLUT_STOREMODE_LOAD); + Texture->VramClut/256, Texture->ClutPSM, Texture->ClutStorageMode, 0, GS_CLUT_STOREMODE_LOAD); } *p_data++ = GS_TEX0_1+gsGlobal->PrimContext; @@ -1192,7 +1192,7 @@ void gsKit_prim_triangle_strip_texture_3d(GSGLOBAL *gsGlobal, GSTEXTURE *Texture { *p_data++ = GS_SETREG_TEX0(Texture->Vram/256, Texture->TBW, Texture->PSM, tw, th, gsGlobal->PrimAlphaEnable, 0, - Texture->VramClut/256, Texture->ClutPSM, 0, 0, GS_CLUT_STOREMODE_LOAD); + Texture->VramClut/256, Texture->ClutPSM, Texture->ClutStorageMode, 0, GS_CLUT_STOREMODE_LOAD); } *p_data++ = GS_TEX0_1+gsGlobal->PrimContext; @@ -1256,7 +1256,7 @@ void gsKit_prim_triangle_fan_texture(GSGLOBAL *gsGlobal, GSTEXTURE *Texture, { *p_data++ = GS_SETREG_TEX0(Texture->Vram/256, Texture->TBW, Texture->PSM, tw, th, gsGlobal->PrimAlphaEnable, 0, - Texture->VramClut/256, Texture->ClutPSM, 0, 0, GS_CLUT_STOREMODE_LOAD); + Texture->VramClut/256, Texture->ClutPSM, Texture->ClutStorageMode, 0, GS_CLUT_STOREMODE_LOAD); } *p_data++ = GS_TEX0_1+gsGlobal->PrimContext; @@ -1320,7 +1320,7 @@ void gsKit_prim_triangle_fan_texture_3d(GSGLOBAL *gsGlobal, GSTEXTURE *Texture, { *p_data++ = GS_SETREG_TEX0(Texture->Vram/256, Texture->TBW, Texture->PSM, tw, th, gsGlobal->PrimAlphaEnable, 0, - Texture->VramClut/256, Texture->ClutPSM, 0, 0, GS_CLUT_STOREMODE_LOAD); + Texture->VramClut/256, Texture->ClutPSM, Texture->ClutStorageMode, 0, GS_CLUT_STOREMODE_LOAD); } *p_data++ = GS_TEX0_1+gsGlobal->PrimContext; @@ -1416,7 +1416,7 @@ void gsKit_prim_quad_texture_3d(GSGLOBAL *gsGlobal, GSTEXTURE *Texture, { *p_data++ = GS_SETREG_TEX0(Texture->Vram/256, Texture->TBW, Texture->PSM, tw, th, gsGlobal->PrimAlphaEnable, 0, - Texture->VramClut/256, Texture->ClutPSM, 0, 0, GS_CLUT_STOREMODE_LOAD); + Texture->VramClut/256, Texture->ClutPSM, Texture->ClutStorageMode, 0, GS_CLUT_STOREMODE_LOAD); } *p_data++ = GS_SETREG_PRIM( GS_PRIM_PRIM_TRISTRIP, 0, 1, gsGlobal->PrimFogEnable, @@ -1511,7 +1511,7 @@ void gsKit_prim_quad_goraud_texture_3d(GSGLOBAL *gsGlobal, GSTEXTURE *Texture, { *p_data++ = GS_SETREG_TEX0(Texture->Vram/256, Texture->TBW, Texture->PSM, tw, th, gsGlobal->PrimAlphaEnable, 0, - Texture->VramClut/256, Texture->ClutPSM, 0, 0, GS_CLUT_STOREMODE_LOAD); + Texture->VramClut/256, Texture->ClutPSM, Texture->ClutStorageMode, 0, GS_CLUT_STOREMODE_LOAD); } *p_data++ = GS_SETREG_PRIM( GS_PRIM_PRIM_TRISTRIP, 1, 1, gsGlobal->PrimFogEnable, diff --git a/examples/clutcsm/clutcsm.c b/examples/clutcsm/clutcsm.c new file mode 100644 index 0000000..3feabaa --- /dev/null +++ b/examples/clutcsm/clutcsm.c @@ -0,0 +1,163 @@ +// ____ ___ | / _____ _____ +// | __ | |___/ | | +// |___| ___| | \ __|__ | gsKit Open Source Project. +// ---------------------------------------------------------------------- +// Copyright 2004 - Chris "Neovanglist" Gilbert +// Licenced under Academic Free License version 2.0 +// Review gsKit README & LICENSE files for further details. +// +// textures.c - Example demonstrating how the 2 different CLUT storage modes work. +// CSMT1 and CSM1 are the two different CLUT storage modes. CSM1 is the default +// mode, and is the mode that is used which requires to have the content swizzled +// before uploading it to the GS. However, CSM2 is a mode that allows you to +// upload the CLUT data directly to the GS, without having to swizzle it first. +// Additionally it allows you to upload a list of CLUTs, and then switch between +// them using the GS_SETCLUT command. +// +// + +#include +#include + +#include +#include +#include +#include +#include + +#define CLUT_SIZE 256 +#define TEXTURE_WIDTH 320 +#define TEXTURE_HEIGHT 240 + +#define USING_CSM1 0 + +#if USING_CSM1 +#define TEXTURE_CLUT_WIDTH 16 +#define TEXTURE_CLUT_HEIGHT 16 +#else +#define TEXTURE_CLUT_WIDTH 256 +#define TEXTURE_CLUT_HEIGHT 1 +#endif + +int main(int argc, char *argv[]) +{ + GSGLOBAL *gsGlobal; + GSTEXTURE tex; + uint32_t i, j, offset; + uint32_t totalVertices = 2; + uint64_t White = GS_SETREG_RGBAQ(0xFF, 0xFF, 0xFF, 0x00, 0x00); + gs_rgbaq color = color_to_RGBAQ(0x80, 0x80, 0x80, 0x80, 0); + + gsGlobal = gsKit_init_global(); + + gsGlobal->PSM = GS_PSM_CT24; + gsGlobal->PSMZ = GS_PSMZ_16S; + + dmaKit_init(D_CTRL_RELE_OFF, D_CTRL_MFD_OFF, D_CTRL_STS_UNSPEC, + D_CTRL_STD_OFF, D_CTRL_RCYC_8, 1 << DMA_CHANNEL_GIF); + + // Initialize the DMAC + dmaKit_chan_init(DMA_CHANNEL_GIF); + + gsKit_init_screen(gsGlobal); + gsKit_mode_switch(gsGlobal, GS_ONESHOT); + + tex.Width = TEXTURE_WIDTH; + tex.Height = TEXTURE_HEIGHT; + tex.PSM = GS_PSM_T8; + tex.ClutPSM = GS_PSM_CT16; + tex.Clut = memalign(128, gsKit_texture_size_ee(CLUT_SIZE, 1, tex.ClutPSM)); + tex.Mem = memalign(128, gsKit_texture_size_ee(tex.Width, tex.Height, tex.PSM)); + tex.Vram = gsKit_vram_alloc(gsGlobal, gsKit_texture_size(tex.Width, tex.Height, GS_PSM_T8), GSKIT_ALLOC_USERBUFFER); + tex.VramClut = gsKit_vram_alloc(gsGlobal, gsKit_texture_size(TEXTURE_CLUT_WIDTH, TEXTURE_CLUT_HEIGHT, GS_PSM_CT16), GSKIT_ALLOC_USERBUFFER); +#if USING_CSM1 + tex.ClutStorageMode = GS_CLUT_STORAGE_CSM1; +#else + tex.ClutStorageMode = GS_CLUT_STORAGE_CSM2; +#endif + + printf("Tex VRAM Range = 0x%X - 0x%X\n", tex.Vram, tex.Vram + gsKit_texture_size(tex.Width, tex.Height, tex.PSM) - 1); + + gsKit_set_clamp(gsGlobal, GS_CMODE_CLAMP); + + uint16_t colors[4] = { + 0xEFFF, + 0x001F, + 0x03E0, + 0x7C00, + }; + + // fill the clut, each 16 positions are the same color + uint16_t *clut = (uint16_t *)tex.Clut; + for (i = 0; i < CLUT_SIZE; i += 16) + { + for (j = 0; j < 16; ++j) + { + clut[i + j] = colors[(i / 16) & 0x3]; + } + } +#if USING_CSM1 + // Swap the texture to have the CSM1 requirements + for (i = 0; i < CLUT_SIZE; i++) + { + if ((i & 0x18) == 8) + { + uint16_t tmp = clut[i]; + clut[i] = clut[i + 8]; + clut[i + 8] = tmp; + } + } +#endif + + // print the clut, 16 colors per line + for (i = 0; i < CLUT_SIZE; i += 16) + { + for (j = 0; j < 16; ++j) + { + printf("%04X ", clut[i + j]); + } + printf("\n"); + } + + // initialize texture, each 16 horizontal pixels are the same color, so let's point to the right color + uint8_t *tex256 = (uint8_t *)tex.Mem; + for (i = 0; i < TEXTURE_HEIGHT; ++i) + { + for (j = 0; j < TEXTURE_WIDTH; ++j) + { + tex256[i * TEXTURE_WIDTH + j] = j & 0xFF; + } + } + + gsKit_texture_send((u32 *)tex.Mem, tex.Width, tex.Height, tex.Vram, tex.PSM, 1, GS_CLUT_TEXTURE); + gsKit_texture_send((u32 *)tex.Clut, TEXTURE_CLUT_WIDTH, TEXTURE_CLUT_HEIGHT, tex.VramClut, tex.ClutPSM, 1, GS_CLUT_PALLETE); + + GSPRIMUVPOINTFLAT *verts = (GSPRIMUVPOINTFLAT *)malloc(sizeof(GSPRIMUVPOINTFLAT) * totalVertices); + verts[0].xyz2 = vertex_to_XYZ2(gsGlobal, 0, 0, 0); + verts[0].uv = vertex_to_UV(&tex, 0, 0); + + verts[1].xyz2 = vertex_to_XYZ2(gsGlobal, gsGlobal->Width, gsGlobal->Height, 0); + verts[1].uv = vertex_to_UV(&tex, tex.Width, tex.Height); + + offset = 0; + + gs_texclut texclut = postion_to_TEXCLUT(4, 0, 0); + + while (1) + { + gsKit_clear(gsGlobal, White); +#if !USING_CSM1 + gsKit_set_texclut(gsGlobal, texclut); +#endif + gskit_prim_list_sprite_texture_uv_flat_color(gsGlobal, &tex, color, totalVertices, verts); + + gsKit_queue_exec(gsGlobal); + gsKit_sync_flip(gsGlobal); + + offset++; + } + + free(verts); + + return 0; +}