Created
February 27, 2022 06:00
-
-
Save F0bes/92d3d9229fc466c80b9430704fc432df to your computer and use it in GitHub Desktop.
Uses the clut buffer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "defs.h" | |
#include <kernel.h> | |
#include <tamtypes.h> | |
#include <stdio.h> | |
#include <gif_tags.h> | |
#include <gs_gp.h> | |
#include <gs_psm.h> | |
#include <dma.h> | |
#include <dma_tags.h> | |
#include <draw.h> | |
#include <graph.h> | |
#include <packet.h> | |
#include <stdlib.h> | |
#include <fcntl.h> | |
#include "colours.c" | |
const u32 WIDTH = 640; | |
const u32 HEIGHT = 480; | |
const s32 FRAME_PSM = GS_PSM_32; | |
#define GS_SETREG_TEST(ate, atst, aref, afail, date, datm, zte, ztst) \ | |
((u64)(ate) | ((u64)(atst) << 1) | \ | |
((u64)(aref) << 4) | ((u64)(afail) << 12) | \ | |
((u64)(date) << 14) | ((u64)(datm) << 15) | \ | |
((u64)(zte) << 16) | ((u64)(ztst) << 17)) | |
int download_from_gs(u32 address, u32 format, const char *fname, int psm_size, int width, int height) | |
{ | |
u32 destBuffer[width * height]; | |
static union | |
{ | |
u32 value_u32[4]; | |
u128 value; | |
} enable_path3 ALIGNED(16) = { | |
{VIF1_MSKPATH3(0), VIF1_NOP, VIF1_NOP, VIF1_NOP}}; | |
u32 prev_imr; | |
u32 prev_chcr; | |
u32 dmaChain[20 * 2] ALIGNED(16); | |
u32 i = 0; // Used to index through the chain | |
u32 *pdma32 = (u32 *)&dmaChain; | |
u64 *pdma64 = (u64 *)(pdma32 + 4); | |
// Set up VIF packet | |
pdma32[i++] = VIF1_NOP; | |
pdma32[i++] = VIF1_MSKPATH3(0x8000); | |
pdma32[i++] = VIF1_FLUSHA; | |
pdma32[i++] = VIF1_DIRECT(6); | |
// Set up our GS packet | |
i = 0; | |
pdma64[i++] = GIFTAG(5, 1, 0, 0, 0, 1); | |
pdma64[i++] = GIF_AD; | |
// pdma64[i++] = GSBITBLTBUF_SET(address / 64, width / 64, format, 0, 0, 0); | |
pdma64[i++] = GSBITBLTBUF_SET(address / 64, width < 64 ? 1 : width / 64, format, 0, 0, 0); | |
pdma64[i++] = GSBITBLTBUF; | |
pdma64[i++] = GSTRXPOS_SET(0, 0, 0, 0, 0); // SSAX, SSAY, DSAX, DSAY, DIR | |
pdma64[i++] = GSTRXPOS; | |
pdma64[i++] = GSTRXREG_SET(width, height); // RRW, RRh | |
pdma64[i++] = GSTRXREG; | |
pdma64[i++] = 0; | |
pdma64[i++] = GSFINISH; | |
pdma64[i++] = GSTRXDIR_SET(1); // XDIR | |
pdma64[i++] = GSTRXDIR; | |
prev_imr = GsPutIMR(GsGetIMR() | 0x0200); | |
prev_chcr = *D1_CHCR; | |
if ((*D1_CHCR & 0x0100) != 0) | |
return 0; | |
// Finish event | |
*GS_CSR = CSR_FINISH; | |
// DMA crap | |
FlushCache(0); | |
printf("DMA stuff\n"); | |
*D1_QWC = 0x7; | |
*D1_MADR = (u32)pdma32; | |
*D1_CHCR = 0x101; | |
asm __volatile__("sync.l\n"); | |
// check if DMA is complete (STR=0) | |
printf("Waiting for DMA channel completion\n"); | |
while (*D1_CHCR & 0x0100) | |
; | |
printf("Waiting for GS_CSR\n"); | |
while ((*GS_CSR & CSR_FINISH) == 0) | |
; | |
printf("Waiting for the vif fifo to empty\n"); | |
// Wait for viffifo to become empty | |
while ((*VIF1_STAT & (0x1f000000))) | |
; | |
// Reverse busdir and transfer image to host | |
*VIF1_STAT = VIF1_STAT_FDR; | |
*GS_BUSDIR = (u64)0x00000001; | |
FlushCache(0); | |
u32 trans_size = ((width * height * psm_size) / 0x100); | |
printf("Download the frame in 2 transfers of qwc 0x%x\n", trans_size); | |
*D1_QWC = trans_size; | |
*D1_MADR = (u32)destBuffer; | |
*D1_CHCR = 0x100; | |
asm __volatile__(" sync.l\n"); | |
// check if DMA is complete (STR=0) | |
while (*D1_CHCR & 0x0100) | |
; | |
*D1_QWC = trans_size; | |
*D1_CHCR = 0x100; | |
asm __volatile__(" sync.l\n"); | |
// Wait for viffifo to become empty | |
while ((*VIF1_STAT & (0x1f000000))) | |
; | |
// check if DMA is complete (STR=0) | |
while (*D1_CHCR & 0x0100) | |
; | |
*D1_CHCR = prev_chcr; | |
asm __volatile__(" sync.l\n"); | |
*VIF1_STAT = 0; | |
*GS_BUSDIR = (u64)0; | |
// Put back prew imr and set finish event | |
GsPutIMR(prev_imr); | |
*GS_CSR = CSR_FINISH; | |
// Enable path3 again | |
*VIF1_FIFO = enable_path3.value; | |
/* | |
Write out to a file | |
*/ | |
FILE *f = fopen(fname, "w+"); | |
if ((u32)f < 0) | |
{ | |
printf("??? couldn't open file, trying usb\n"); | |
} | |
printf("File should be size %d\n", (psm_size / 8) * width * height); | |
fwrite(destBuffer, psm_size / 8, width * height, f); | |
fclose(f); | |
return 0; | |
} | |
int main(void) | |
{ | |
(*(volatile u_int *)0x10003000) = 1; | |
/* | |
Initialize graph | |
*/ | |
framebuffer_t fb; | |
fb.width = WIDTH; | |
fb.height = HEIGHT; | |
fb.psm = FRAME_PSM; | |
fb.mask = 0x00000000; | |
fb.address = graph_vram_allocate(fb.width, fb.height, fb.psm, GRAPH_ALIGN_PAGE); | |
zbuffer_t zb; | |
zb.enable = 1; | |
zb.zsm = GS_ZBUF_32; | |
zb.address = graph_vram_allocate(fb.width, fb.height, zb.zsm, GRAPH_ALIGN_PAGE); | |
zb.mask = 0; | |
zb.method = ZTEST_METHOD_ALLPASS; | |
int clutAddress = graph_vram_allocate(16, 16, GS_PSM_32, GRAPH_ALIGN_BLOCK); | |
int texAddress = graph_vram_allocate(16, 16, GS_PSM_8, GRAPH_ALIGN_BLOCK); | |
graph_initialize(fb.address, fb.width, fb.height, fb.psm, 0, 0); | |
dma_channel_initialize(DMA_CHANNEL_GIF, NULL, 0); | |
dma_channel_fast_waits(DMA_CHANNEL_GIF); | |
/* | |
Init drawing stuff | |
*/ | |
packet_t *packet = packet_init(100, PACKET_NORMAL); | |
qword_t *q = packet->data; | |
q = draw_setup_environment(q, 0, &fb, &zb); | |
q = draw_primitive_xyoffset(q, 0, 0, 0); | |
q = draw_enable_tests(q, 0, &zb); | |
q = draw_finish(q); | |
dma_channel_send_normal(DMA_CHANNEL_GIF, packet->data, q - packet->data, 0, 0); | |
draw_wait_finish(); | |
/* | |
Upload texture | |
*/ | |
q = packet->data; | |
u8* textureBuffer = (u8*)malloc(256); | |
for (int i = 0; i < 16 * 16; i++) | |
{ | |
textureBuffer[i] = i; | |
} | |
FlushCache(0); | |
texbuffer_t tb; | |
tb.width = 16; | |
tb.psm = GS_PSM_8; | |
tb.address = texAddress; | |
q = draw_texture_transfer(q, textureBuffer, tb.width, tb.width, tb.psm, tb.address, 64); | |
q = draw_texture_flush(q); | |
dma_channel_send_chain(DMA_CHANNEL_GIF, packet->data, q - packet->data, 0, 0); | |
dma_wait_fast(); | |
// Upload clut | |
q = packet->data; | |
texbuffer_t tbc; | |
tbc.width = 16; | |
tbc.psm = GS_PSM_32; | |
tbc.address = clutAddress; | |
q = draw_texture_transfer(q, &colours[0], tbc.width, tbc.width, tbc.psm, tbc.address, 64); | |
q = draw_texture_flush(q); | |
dma_channel_send_chain(DMA_CHANNEL_GIF, packet->data, q - packet->data, 0, 0); | |
dma_wait_fast(); | |
printf("Uploading linear 8 bit texture\n"); | |
/* | |
Now draw something | |
*/ | |
/* | |
printf("Clearing screen\n"); | |
q = packet->data; | |
// Draw a full screen sprite | |
PACK_GIFTAG(q, GIF_SET_TAG(1, 1, GIF_PRE_ENABLE, GIF_PRIM_SPRITE, GIF_FLG_PACKED, 5), | |
GIF_REG_AD | (GIF_REG_AD << 4)| (GIF_REG_RGBAQ << 8) | (GIF_REG_XYZ2 << 12) | (GIF_REG_XYZ2 << 16)); | |
q++; | |
q->dw[0] = GS_SETREG_TEST(0, 0, 0, 0, 0, 0, 1, 1); | |
q->dw[1] = GS_REG_TEST; | |
q++; | |
q->dw[0] = GS_SET_FRAME(fb.address / 64,fb.width / 64,fb.psm,0); | |
q->dw[1] = GS_REG_FRAME; | |
q++; | |
// RGBAQ | |
q->dw[0] = (u64)((0) | ((u64)0x00 << 32)); | |
q->dw[1] = (u64)((0x0) | ((u64)0x00 << 32)); | |
q++; | |
// XYZ2 | |
q->dw[0] = (u64)((((0 << 4)) | (((u64)(0 << 4)) << 32))); | |
q->dw[1] = (u64)(0); | |
q++; | |
// XYZ2 | |
q->dw[0] = (u64)((((640 << 4)) | (((u64)(480 << 4)) << 32))); | |
q->dw[1] = (u64)(0); | |
q++; | |
q = draw_finish(q); | |
dma_channel_send_normal(DMA_CHANNEL_GIF, packet->data, q - packet->data, 0, 0); | |
draw_wait_finish(); | |
*/ | |
int frame = 0; | |
// while (1) | |
{ | |
frame++; | |
if (frame % 500) | |
{ | |
printf("500Frames\n"); | |
// allows me to reset ps2link | |
} | |
// TEXFLUSH | |
q = packet->data; | |
PACK_GIFTAG(q, GIF_SET_TAG(1, 1, 0, 0, GIF_FLG_PACKED, 1), GIF_REG_AD); | |
q++; | |
PACK_GIFTAG(q, 1, GS_REG_TEXFLUSH); | |
q++; | |
dma_channel_send_normal(DMA_CHANNEL_GIF, packet->data, q - packet->data, 0, 0); | |
// Wait until the drawing is finished. | |
// Draw the triangles | |
q = packet->data; | |
PACK_GIFTAG(q, GIF_SET_TAG(1, 1, GIF_PRE_ENABLE, GIF_SET_PRIM(GIF_PRIM_SPRITE, 0, 1, 0, 0, 0, 1, 0, 0), GIF_FLG_PACKED, 6), | |
GIF_REG_AD | (GIF_REG_RGBAQ << 4) | (GIF_REG_UV << 8) | (GIF_REG_XYZ2 << 12) | (GIF_REG_UV << 16) | (GIF_REG_XYZ2 << 20)); | |
q++; | |
// TEST1 | |
q->dw[0] = GS_SET_TEX0(tb.address / 64, 1, GS_PSM_8, 4, 4, 1, 1, clutAddress / 64, GS_PSM_32, 0, 0, 1); | |
q->dw[1] = GS_REG_TEX0; | |
q++; | |
// RGBAQ (Q will default to 1.0f on new tag) | |
q->dw[0] = (u64)((0) | ((u64)0xcc << 32)); | |
q->dw[1] = (u64)((0xcc) | ((u64)0xFF << 32)); | |
q++; | |
// UV | |
q->dw[0] = GIF_SET_ST(0 << 4, 0 << 4); | |
q->dw[1] = 0; | |
q++; | |
// XYZ2 | |
q->dw[0] = (u64)((((0 << 4)) | (((u64)(200 << 4)) << 32))); | |
q->dw[1] = (u64)(0x1000); | |
q++; | |
// UV | |
q->dw[0] = GIF_SET_ST(16 << 4, 16 << 4); | |
q->dw[1] = 0; | |
q++; | |
// XYZ2 | |
q->dw[0] = (u64)(((200 << 4)) | (((u64)(0 << 4)) << 32)); | |
q->dw[1] = (u64)(0x1000); | |
q++; | |
q = draw_finish(q); | |
dma_channel_send_normal(DMA_CHANNEL_GIF, packet->data, q - packet->data, 0, 0); | |
// Wait until the drawing is finished. | |
draw_wait_finish(); | |
/* | |
q = packet->data; | |
PACK_GIFTAG(q, GIF_SET_TAG(1, 1, GIF_PRE_ENABLE, GIF_PRIM_TRIANGLE, GIF_FLG_PACKED, 5), | |
GIF_REG_AD | (GIF_REG_RGBAQ << 4) | (GIF_REG_XYZ2 << 8) | (GIF_REG_XYZ2 << 12) | (GIF_REG_XYZ2 << 16)); | |
q++; | |
// TEST1 | |
q->dw[0] = GS_SET_TEST(0, 0, 0, 0, 0, 0, 1, 1); | |
q->dw[1] = GS_REG_TEST; | |
q++; | |
// RGBAQ (Q will default to 1.0f on new tag) | |
q->dw[0] = (u64)((0) | ((u64)0xcc << 32)); | |
q->dw[1] = (u64)((0xcc) | ((u64)0xFF << 32)); | |
q++; | |
// XYZ2 | |
q->dw[0] = (u64)((((200 << 4)) | (((u64)(100 << 4)) << 32))); | |
q->dw[1] = (u64)(0x1000); | |
q++; | |
// XYZ2 | |
q->dw[0] = (u64)(((100 << 4)) | (((u64)(200 << 4)) << 32)); | |
q->dw[1] = (u64)(0x1000); | |
q++; | |
// XYZ2 | |
q->dw[0] = (u64)(((200 << 4)) | (((u64)(200 << 4)) << 32)); | |
q->dw[1] = (u64)(0x1000); | |
q++; | |
q = draw_finish(q); | |
dma_channel_send_normal(DMA_CHANNEL_GIF, packet->data, q - packet->data, 0, 0); | |
// Wait until the drawing is finished. | |
draw_wait_finish(); | |
*/ | |
// Now initiate vsync. | |
graph_wait_vsync(); | |
} | |
/* | |
Now we can download the framebuffer | |
You might have to change some stuff if you use a different format from CT24 | |
*/ | |
download_from_gs(fb.address, GS_PSM_32, "framebuffer.raw",32,WIDTH,HEIGHT); | |
download_from_gs(tbc.address, GS_PSM_32, "clut.raw", 32, 16, 16); | |
SleepThread(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment