//--------------------------------------------------------------------------- void g2_fill_rect(s16 x0, s16 y0, s16 x1, s16 y1) { x0 += gs_origin_x; y0 += gs_origin_y; x1 += gs_origin_x; y1 += gs_origin_y; BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 4, 1, 0, 0, 0); GIF_DATA_AD(gs_dma_buf, prim, GS_PRIM(PRIM_SPRITE, 0, 0, 0, 0, 0, 0, 0, 0)); GIF_DATA_AD(gs_dma_buf, rgbaq, GS_RGBAQ(g2_fill_r, g2_fill_g, g2_fill_b, 0x80, 0)); GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2(x0<<4, y0<<4, 0)); // It looks like the default operation for the SPRITE primitive is to // not draw the right and bottom 'lines' of the rectangle refined by // the parameters. Add +1 to change this. GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2((x1+1)<<4, (y1+1)<<4, 0)); SEND_GS_PACKET(gs_dma_buf); }
//--------------------------------------------------------------------------- void gs_load_texture(u16 x, u16 y, u16 w, u16 h, u32 data_adr, u32 dest_adr, u16 dest_w) { u32 i; // DMA buffer loop counter u32 frac; // flag for whether to run a fractional buffer or not u32 current; // number of pixels to transfer in current DMA u32 qtotal; // total number of qwords of data to transfer BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 4, 1, 0, 0, 0); GIF_DATA_AD(gs_dma_buf, bitbltbuf, GS_BITBLTBUF(0, 0, 0, dest_adr/256, // frame buffer address dest_w/64, // frame buffer width 0)); GIF_DATA_AD(gs_dma_buf, trxpos, GS_TRXPOS( 0, 0, x, y, 0)); // left to right/top to bottom GIF_DATA_AD(gs_dma_buf, trxreg, GS_TRXREG(w, h)); GIF_DATA_AD(gs_dma_buf, trxdir, GS_TRXDIR(XDIR_EE_GS)); SEND_GS_PACKET(gs_dma_buf); qtotal = w*h/4; // total number of quadwords to transfer. current = qtotal % MAX_TRANSFER;// work out if a partial buffer transfer is needed. frac=1; // assume yes. if(!current) // if there is no need for partial buffer { current = MAX_TRANSFER; // start with a full buffer frac=0; // and don't do extra partial buffer first } for(i=0; i<(qtotal/MAX_TRANSFER)+frac; i++) { BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_IMG(gs_dma_buf, current); SEND_GS_PACKET(gs_dma_buf); SET_QWC(GIF_QWC, current); SET_MADR(GIF_MADR, data_adr, 0); SET_CHCR(GIF_CHCR, 1, 0, 0, 0, 0, 1, 0); DMA_WAIT(GIF_CHCR); data_adr += current*16; current = MAX_TRANSFER; // after the first one, all are full buffers } // Access the TEXFLUSH register with anything to flush the texture BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 1, 1, 0, 0, 0); GIF_DATA_AD(gs_dma_buf, texflush, 0x42); SEND_GS_PACKET(gs_dma_buf); }
void gsUpdateContext(void) { GsState *gs = gsCurState; GIF_BEGIN_PACKET(gifDmaBuf); GIF_TAG(gifDmaBuf, 2, 1, 0, 0, 0, 1, 0x0e); GIF_DATA_AD(gifDmaBuf, GS_TEST_1, MAKE_GS_TEST(0, 0, 0, 0, 0, 0, gs->ztest, gs->zfunc)); GIF_DATA_AD(gifDmaBuf, GS_ALPHA_1, MAKE_GS_ALPHA(gs->blend.a, gs->blend.b, gs->blend.c, gs->blend.d, gs->blend.fix)); GIF_SEND_PACKET(gifDmaBuf); }
//--------------------------------------------------------------------------- void g2_line(s16 x0, s16 y0, s16 x1, s16 y1) { x0 += gs_origin_x; y0 += gs_origin_y; x1 += gs_origin_x; y1 += gs_origin_y; BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 4, 1, 0, 0, 0); GIF_DATA_AD(gs_dma_buf, prim, GS_PRIM(PRIM_LINE, 0, 0, 0, 0, 0, 0, 0, 0)); GIF_DATA_AD(gs_dma_buf, rgbaq, GS_RGBAQ(g2_col_r, g2_col_g, g2_col_b, 0x80, 0)); GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2(x0<<4, y0<<4, 0)); GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2(x1<<4, y1<<4, 0)); SEND_GS_PACKET(gs_dma_buf); }
void gsClear(void) { struct GsState *gs = gsCurState; uint16 x, y; int r = gs->clearcol & 0xFF; int g = (gs->clearcol >> 8) & 0xFF; int b = (gs->clearcol >> 16) & 0xFF; int a = (gs->clearcol >> 24) & 0xFF; x = (gs->width << 4) + gs->xoff; y = (gs->height << 4) + gs->yoff; GIF_BEGIN_PACKET(gifDmaBuf); GIF_TAG(gifDmaBuf, 6, 1, 0, 0, 0, 1, 0x0e); /* clear z-buffer too */ GIF_DATA_AD(gifDmaBuf, GS_TEST_1, MAKE_GS_TEST(0, 0, 0, 0, 0, 0, 1, ZTST_ALWAYS)); GIF_DATA_AD(gifDmaBuf, GS_PRIM, MAKE_GS_PRIM(PRIM_SPRITE, 0, 0, 0, 0, 0, 0, 0, 0)); GIF_DATA_AD(gifDmaBuf, GS_RGBAQ, MAKE_GS_RGBAQ(r, g, b, a, 0)); GIF_DATA_AD(gifDmaBuf, GS_XYZ2, MAKE_GS_XYZ(0, 0, 0)); GIF_DATA_AD(gifDmaBuf, GS_XYZ2, MAKE_GS_XYZ(x, y, 0)); /* re-enable z-test */ GIF_DATA_AD(gifDmaBuf, GS_TEST_1, MAKE_GS_TEST(0, 0, 0, 0, 0, 0, gs->ztest, gs->zfunc)); GIF_SEND_PACKET(gifDmaBuf); }
void gsSelectActiveFb(int n) { struct GsState *g = gsCurState; int addr; addr = g->fbAddr[n]/4/2048; GIF_BEGIN_PACKET(gifDmaBuf); GIF_TAG(gifDmaBuf, 1, 1, 0, 0, 0, 1, 0x0e); GIF_DATA_AD(gifDmaBuf, GS_FRAME_1, MAKE_GS_FRAME(addr, g->width/64, g->psm, 0)); GIF_SEND_PACKET(gifDmaBuf); }
//--------------------------------------------------------------------------- void g2_put_pixel(s16 x, s16 y) { x += gs_origin_x; y += gs_origin_y; BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 4, 1, 0, 0, 0); GIF_DATA_AD(gs_dma_buf, prim, GS_PRIM(PRIM_POINT, 0, 0, 0, 0, 0, 0, 0, 0)); GIF_DATA_AD(gs_dma_buf, rgbaq, GS_RGBAQ(g2_col_r, g2_col_g, g2_col_b, 0x80, 0)); // The XYZ coordinates are actually floating point numbers between // 0 and 4096 represented as unsigned integers where the lowest order // four bits are the fractional point. That's why all coordinates are // shifted left 4 bits. GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2(x<<4, y<<4, 0)); SEND_GS_PACKET(gs_dma_buf); }
void drawrect(uint16 x1, uint16 y1, uint16 x2, uint16 y2, uint32 col) { struct GsState *gs = gsCurState; x1 = (x1<<4) + gs->xoff; y1 = (y1<<4) + gs->yoff; x2 = (x2<<4) + gs->xoff; y2 = (y2<<4) + gs->yoff; int r = col & 0xFF; int g = (col >> 8) & 0xFF; int b = (col >> 16) & 0xFF; int a = (col >> 24) & 0xFF; GIF_BEGIN_PACKET(gifDmaBuf); GIF_TAG(gifDmaBuf, 4, 1, 0, 0, 0, 1, 0x0e); GIF_DATA_AD(gifDmaBuf, GS_PRIM, MAKE_GS_PRIM(PRIM_SPRITE, 0, 0, 0, gs->blend.enable, 0, 0, 0, 0)); GIF_DATA_AD(gifDmaBuf, GS_RGBAQ, MAKE_GS_RGBAQ(r, g, b, a, 0)); GIF_DATA_AD(gifDmaBuf, GS_XYZ2, MAKE_GS_XYZ(x1, y1, 0)); GIF_DATA_AD(gifDmaBuf, GS_XYZ2, MAKE_GS_XYZ(x2, y2, 0)); GIF_SEND_PACKET(gifDmaBuf); }
//--------------------------------------------------------------------------- void g2_set_viewport(u16 x0, u16 y0, u16 x1, u16 y1) { g2_view_x0 = x0; g2_view_x1 = x1; g2_view_y0 = y0; g2_view_y1 = y1; BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 1, 1, 0, 0, 0); GIF_DATA_AD(gs_dma_buf, scissor_1, GS_SCISSOR(x0, x1, y0, y1)); SEND_GS_PACKET(gs_dma_buf); }
//--------------------------------------------------------------------------- void g2_set_active_frame(u8 frame) { BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 1, 1, 0, 0, 0); GIF_DATA_AD(gs_dma_buf, frame_1, GS_FRAME( g2_frame_addr[frame]/8192, // FrameBuffer base pointer = Address/8192 cur_mode->width/64, // Frame buffer width (Pixels/64) cur_mode->psm, // Pixel Storage Format 0)); SEND_GS_PACKET(gs_dma_buf); g2_active_frame = frame; }
//--------------------------------------------------------------------------- void g2_put_image(s16 x, s16 y, s16 w, s16 h, u32 *data) { x += gs_origin_x; y += gs_origin_y; // - Call this to copy the texture data from EE memory to GS memory. // - The g2_texbuf_addr variable holds the byte address of the // 'texture buffer' and is setup in g2_init() to be just after // the frame buffer(s). When only the standard resolutions are // used this buffer is guaranteed to be correctly aligned on 256 // bytes. gs_load_texture(0, 0, w, h, (u32)data, g2_texbuf_addr, g2_max_x+1); BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 6, 1, 0, 0, 0); // Setup the Texture Buffer register. Note the width and height! They // must both be a power of 2. GIF_DATA_AD(gs_dma_buf, tex0_1, GS_TEX0( g2_texbuf_addr/256, // base pointer (g2_max_x+1)/64, // width 0, // 32bit RGBA gs_texture_wh(w), // width gs_texture_wh(h), // height 1, // RGBA TEX_DECAL, // just overwrite existing pixels 0,0,0,0,0)); GIF_DATA_AD(gs_dma_buf, prim, GS_PRIM(PRIM_SPRITE, 0, // flat shading 1, // texture mapping ON 0, 0, 0, // no fog, alpha, or antialiasing 1, // use UV register for coordinates. 0, 0)); // Texture and vertex coordinates are specified consistently, with // the last four bits being the decimal part (always X.0 here). // Top/Left, texture coordinates (0, 0). GIF_DATA_AD(gs_dma_buf, uv, GS_UV(0, 0)); GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2(x<<4, y<<4, 0)); // Bottom/Right, texture coordinates (w, h). GIF_DATA_AD(gs_dma_buf, uv, GS_UV(w<<4, h<<4)); GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2((x+w)<<4, (y+h)<<4, 0)); // Finally send the command buffer to the GIF. SEND_GS_PACKET(gs_dma_buf); }
void gsInit(void) { struct GsState *g = gsCurState; int addr0, addr1; g->visibleFb = 0; g->activeFb = 1; printf("%d %d\n", g->fbAddr[0], g->fbAddr[1]); addr0 = g->fbAddr[g->visibleFb]/4/2048; addr1 = g->fbAddr[g->activeFb]/4/2048; GS_RESET(); __asm__("sync.p; nop"); SET_REG64(GS_CSR, 0); GsPutIMR(0xff00); SetGsCrt(g->interlaced, g->mode, g->field); SET_REG64(GS_PMODE, MAKE_GS_PMODE(0, 1, 0, 1, 0, 0xFF)); SET_REG64(GS_DISPFB2, MAKE_GS_DISPFB(addr0, g->width/64, g->psm, 0, 0)); SET_REG64(GS_DISPFB1, MAKE_GS_DISPFB(addr0, g->width/64, g->psm, 0, 0)); SET_REG64(GS_DISPLAY2, MAKE_GS_DISPLAY(g->startx, g->starty, g->magh, g->magv, g->dw-1, g->dh-1)); SET_REG64(GS_DISPLAY1, MAKE_GS_DISPLAY(g->startx, g->starty, g->magh, g->magv, g->dw-1, g->dh-1)); SET_REG64(GS_BGCOLOR, MAKE_GS_BGCOLOR(100, 100, 100)); GIF_BEGIN_PACKET(gifDmaBuf); GIF_TAG(gifDmaBuf, 7, 1, 0, 0, 0, 1, 0x0e); GIF_DATA_AD(gifDmaBuf, GS_PRMODECONT, MAKE_GS_PRMODECONT(1)); GIF_DATA_AD(gifDmaBuf, GS_FRAME_1, MAKE_GS_FRAME(addr1, g->width/64, g->psm, 0)); GIF_DATA_AD(gifDmaBuf, GS_ZBUF_1, MAKE_GS_ZBUF(g->zbAddr/4/2048, g->zpsm, 0)); GIF_DATA_AD(gifDmaBuf, GS_XYOFFSET_1, MAKE_GS_XYOFFSET(g->xoff, g->yoff)); GIF_DATA_AD(gifDmaBuf, GS_SCISSOR_1, MAKE_GS_SCISSOR(0, g->xmax, 0, g->ymax)); GIF_DATA_AD(gifDmaBuf, GS_TEST_1, MAKE_GS_TEST(0, 0, 0, 0, 0, 0, g->ztest, g->zfunc)); GIF_DATA_AD(gifDmaBuf, GS_COLCLAMP, MAKE_GS_COLCLAMP(1)); GIF_SEND_PACKET(gifDmaBuf); }
//--------------------------------------------------------------------------- void g2_set_font_color(u8 red, u8 green, u8 blue) { u64 x0; u64 y0; u64 x1; u64 y1; x0 = gs_origin_x-10; y0 = gs_origin_y-10; x1 = g2_fontbuf_w + gs_origin_x; y1 = g2_fontbuf_h + gs_origin_y; BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 6, 1, 0, 0, 0); // Restore the frame buffer to the current active frame buffer. GIF_DATA_AD(gs_dma_buf, frame_1, GS_FRAME( g2_fontbuf_addr/8192, cur_mode->width/64, cur_mode->psm, 0)); // Draw the colored rectangle over the entire Font Bitmap. GIF_DATA_AD(gs_dma_buf, prim, GS_PRIM(PRIM_LINE, 0, 0, 0, 0, 0, 0, 0, 0)); // GS_PRIM(PRIM_SPRITE, 0, 0, 0, 0, 0, 0, 0, 0)); GIF_DATA_AD(gs_dma_buf, rgbaq, GS_RGBAQ(red, green, blue, 0x80, 0)); GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2(x0<<4, y0<<4, 0)); GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2(x1<<4, y1<<4, 0)); // Restore the frame buffer to the current active frame buffer. GIF_DATA_AD(gs_dma_buf, frame_1, GS_FRAME( g2_frame_addr[g2_active_frame]/8192, cur_mode->width/64, cur_mode->psm, 0)); SEND_GS_PACKET(gs_dma_buf); }
//--------------------------------------------------------------------------- int g2_init(g2_video_mode mode) { vmode_t *v; v = &(vmodes[mode]); cur_mode = v; g2_max_x = v->width - 1; g2_max_y = v->height - 1; g2_view_x0 = 0; g2_view_y0 = 0; g2_view_x1 = g2_max_x; g2_view_y1 = g2_max_y; gs_origin_x = 1024; gs_origin_y = 1024; gs_mem_current = 0; // nothing allocated yet g2_visible_frame = 0; // display frame 0 g2_active_frame = 0; // draw to frame 0 // - Initialize the DMA. // - Writes a 0 to most of the DMA registers. dma_reset(); // - Sets the RESET bit if the GS CSR register. GS_RESET(); #ifndef FLASH // - Can someone please tell me what the sync.p // instruction does. Synchronizes something :-) __asm__(" sync.p nop "); #endif // - Sets up the GS IMR register (i guess). // - The IMR register is used to mask and unmask certain interrupts, // for example VSync and HSync. We'll use this properly in Tutorial 2. // - Does anyone have code to do this without using the 0x71 syscall? // - I havn't gotten around to looking at any PS2 bios code yet. gs_set_imr(); // - Use syscall 0x02 to setup some video mode stuff. // - Pretty self explanatory I think. // - Does anyone have code to do this without using the syscall? It looks // like it should only set the SMODE2 register, but if I remove this syscall // and set the SMODE2 register myself, it donesn't work. What else does // syscall 0x02 do? gs_set_crtc(NON_INTERLACED, v->ntsc_pal, FRAME); // - I havn't attempted to understand what the Alpha parameters can do. They // have been blindly copied from the 3stars demo (although they don't seem // do have any impact in this simple 2D code. GS_SET_PMODE( 0, // ReadCircuit1 OFF 1, // ReadCircuit2 ON 1, // Use ALP register for Alpha Blending 1, // Alpha Value of ReadCircuit2 for output selection 0, // Blend Alpha with the output of ReadCircuit2 0xFF // Alpha Value = 1.0 ); /* // - Non needed if we use gs_set_crt() GS_SET_SMODE2( 0, // Non-Interlaced mode 1, // FRAME mode (read every line) 0 // VESA DPMS Mode = ON ??? please explain ??? ); */ GS_SET_DISPFB2( 0, // Frame Buffer base pointer = 0 (Address/8192) v->width/64, // Buffer Width (Pixels/64) v->psm, // Pixel Storage Format 0, // Upper Left X in Buffer = 0 0 // Upper Left Y in Buffer = 0 ); // Why doesn't (0, 0) equal the very top-left of the TV? GS_SET_DISPLAY2( 656, // X position in the display area (in VCK units) 36, // Y position in the display area (in Raster units) v->magh-1, // Horizontal Magnification - 1 0, // Vertical Magnification = 1x v->width*v->magh-1, // Display area width - 1 (in VCK units) (Width*HMag-1) v->height-1 // Display area height - 1 (in pixels) (Height-1) ); GS_SET_BGCOLOR( 0, // RED 0, // GREEN 0 // BLUE ); BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 6, 1, 0, 0, 0); // Use drawing parameters from PRIM register GIF_DATA_AD(gs_dma_buf, prmodecont, 1); // Setup frame buffers. Point to 0 initially. GIF_DATA_AD(gs_dma_buf, frame_1, GS_FRAME( 0, // FrameBuffer base pointer = 0 (Address/8192) v->width/64, // Frame buffer width (Pixels/64) v->psm, // Pixel Storage Format 0)); // Save address and advance GS memory pointer by buffer size (in bytes) // Do this for both frame buffers. g2_frame_addr[0] = gs_mem_current; gs_mem_current += v->width * v->height * (v->bpp/8); g2_frame_addr[1] = gs_mem_current; gs_mem_current += v->width * v->height * (v->bpp/8); // Displacement between Primitive and Window coordinate systems. GIF_DATA_AD(gs_dma_buf, xyoffset_1, GS_XYOFFSET( gs_origin_x<<4, gs_origin_y<<4)); // Clip to frame buffer. GIF_DATA_AD(gs_dma_buf, scissor_1, GS_SCISSOR( 0, g2_max_x, 0, g2_max_y)); // Create a single 256x128 font buffer g2_fontbuf_addr = gs_mem_current; gs_mem_current += g2_fontbuf_w * g2_fontbuf_h * (v->bpp/8); // Create a texture buffer as big as the screen. // Just save the address advance GS memory pointer by buffer size (in bytes) // The TEX registers are set later, when drawing. g2_texbuf_addr = gs_mem_current; gs_mem_current += v->width * v->height * (v->bpp/8); // Setup test_1 register to allow transparent texture regions where A=0 GIF_DATA_AD(gs_dma_buf, test_1, GS_TEST( 1, // Alpha Test ON ATST_NOTEQUAL, 0x00, // Reject pixels with A=0 AFAIL_KEEP, // Don't update frame or Z buffers 0, 0, 0, 0)); // No Destination Alpha or Z-Buffer Tests // Setup the ALPHA_1 register to correctly blend edges of // pre-antialiased fonts using Alpha Blending stage. // The blending formula is // PIXEL=(SRC-FRAME)*SRC_ALPHA>>7+FRAME GIF_DATA_AD(gs_dma_buf, alpha_1, GS_ALPHA( 0, // A - source 1, // B - frame buffer 0, // C - alpha from source 1, // D - frame buffer 0)); // FIX - not needed SEND_GS_PACKET(gs_dma_buf); return(1); }
//--------------------------------------------------------------------------- void g2_out_text(s16 x, s16 y, char *str) { char c; // current character u16 *tc; // current texture coordinates [4] u16 x0, y0, x1, y1; // rectangle for current character u16 w, h; // width and height of above rectangle x += gs_origin_x; y += gs_origin_y; c = *str; while(c) { // Read the texture coordinates for current character tc = &g2_font_tc[c*4]; x0 = *tc++; y0 = *tc++; x1 = *tc++; y1 = *tc++; w = x1-x0+1; h = y1-y0+1; // Draw a sprite with current character mapped onto it BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 6, 1, 0, 0, 0); GIF_DATA_AD(gs_dma_buf, tex0_1, GS_TEX0( g2_fontbuf_addr/256, // base pointer (g2_fontbuf_w)/64, // width 0, // 32bit RGBA gs_texture_wh(g2_fontbuf_w),// width gs_texture_wh(g2_fontbuf_w),// height 1, // RGBA TEX_DECAL, // just overwrite existing pixels 0,0,0,0,0)); /* GIF_DATA_AD(gs_dma_buf, tex1_1, GS_TEX1( 0, 0, FILTER_LINEAR, FILTER_LINEAR, 0, 0, 0)); GIF_DATA_AD(gs_dma_buf, clamp_1, 0x05); */ GIF_DATA_AD(gs_dma_buf, prim, GS_PRIM(PRIM_SPRITE, 0, // flat shading 1, // texture mapping ON 0, 1, 0, // no fog or antialiasing, but use alpha 1, // use UV register for coordinates. 0, 0)); GIF_DATA_AD(gs_dma_buf, uv, GS_UV(x0<<4, y0<<4)); GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2(x<<4, y<<4, 0)); GIF_DATA_AD(gs_dma_buf, uv, GS_UV((x1+1)<<4, (y1+1)<<4)); GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2( (x+w*g2_font_mag)<<4, (y+h*g2_font_mag)<<4, 0)); SEND_GS_PACKET(gs_dma_buf); // Advance drawing position x += (w + g2_font_spacing) * g2_font_mag; // Get next character str++; c = *str; } }