Skip to content

Instantly share code, notes, and snippets.

@F0bes
Last active February 27, 2022 03:50
Show Gist options
  • Save F0bes/64492c16777f309d69d551360d0767bb to your computer and use it in GitHub Desktop.
Save F0bes/64492c16777f309d69d551360d0767bb to your computer and use it in GitHub Desktop.
#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)
{
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;
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 = 0;
if (psm_size == 32)
trans_size = 0x9600;
else if (psm_size == 24)
trans_size = 0x7080;
else if (psm_size == 16)
trans_size = 0x4B00;
else if (psm_size == 8)
trans_size = 0x2580;
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;
}
char textureStrip[16 * 16];
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_PAGE); // Might be able to align by block??? whatever
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();
printf("Uploading texture to be used as a clut texture\n");
/*
Upload texture (clut)
*/
packet_free(packet);
packet = packet_init(50, PACKET_NORMAL);
q = packet->data;
texbuffer_t tbc;
tbc.width = 16;
tbc.psm = GS_PSM_32;
tbc.address = clutAddress;
q = draw_texture_transfer(q, colours, 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");
/*
Upload texture
*/
q = packet->data;
for (int i = 0; i < 16 * 16; i++)
{
textureStrip[i] = i;
}
texbuffer_t tb;
tb.width = 16;
tb.psm = GS_PSM_8;
tb.address = graph_vram_allocate(16, 16, GS_PSM_8, GRAPH_ALIGN_BLOCK);
q = draw_texture_transfer(q, &textureStrip[0], 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();
/*
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(zb.address, GS_PSM_, "zbuffer.raw",32);
download_from_gs(fb.address, GS_PSM_32, "framebuffer.raw", 32);
SleepThread();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment