Welcome! Log In Create A New Profile

Advanced

GX issue

Posted by Plombo 
GX issue
May 22, 2010 01:42AM
I have a problem with GX in my program. The below code causes the screen to constantly appear as a jumble of the current frame and recently rendered frames. Only parts of the screen are updated every time it renders a new frame. When the screen stays the same for a few seconds, the screen gradually undistorts itself.

Note: Since it's not entirely clear from the code, pixelformat == PIXEL_8. I haven't tested 16-bit or 32-bit color mode yet.

Here's my code:
#include <ogcsys.h>
#include <malloc.h>
#include <string.h>
#include "vga.h"
#include "types.h"
#include "screen.h"
#include "globals.h"
 
#define DEFAULT_FIFO_SIZE	(256*1024)

static unsigned char gp_fifo[DEFAULT_FIFO_SIZE] ATTRIBUTE_ALIGN (32);
static void *xfb[2] = { NULL, NULL };
static GXRModeObj *vmode;
static GXTexObj texObj;
static Mtx44 perspective;
static Mtx GXmodelView2D;
static unsigned short palette[256];

void *textureMem = NULL;
int whichbuffer = 0;
int screenWidth, screenHeight; // resolution of TV screen
int xOffset, yOffset;
int scaledWidth, scaledHeight;
int textureWidth, textureHeight; // dimensions of game screen
float yscale; // scale factor from EFB to XFB

void drawSpriteTex(int x, int y, int width, int height);

static void video_gx_init()
{
	GXColor background = { 0, 0, 0, 0xff };
	
	// clear out FIFO area and initialize GX
	memset(gp_fifo,0,DEFAULT_FIFO_SIZE);
	GX_Init(gp_fifo,DEFAULT_FIFO_SIZE);
 
	// clears the screen to black and clears the z buffer
	GX_SetCopyClear(background, 0x00ffffff);
 
	// other GX setup
	GX_SetViewport(0,0,vmode->fbWidth,vmode->efbHeight,0,1);
	yscale = GX_GetYScaleFactor(vmode->efbHeight,vmode->xfbHeight);
	GX_SetDispCopyYScale(yscale);
	GX_SetScissor(0,0,vmode->fbWidth,vmode->efbHeight);
	GX_SetDispCopySrc(0,0,vmode->fbWidth,vmode->efbHeight);
	GX_SetDispCopyDst(vmode->fbWidth,vmode->xfbHeight);
	GX_SetCopyFilter(vmode->aa,vmode->sample_pattern,GX_TRUE,vmode->vfilter);
	GX_SetFieldMode(vmode->field_rendering,((vmode->viHeight==2*vmode->xfbHeight)?GX_ENABLE:GX_DISABLE));

	if (vmode->aa)
		GX_SetPixelFmt(GX_PF_RGB565_Z16, GX_ZC_LINEAR);
	else
		GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);

	GX_SetCullMode(GX_CULL_NONE);
	GX_SetDispCopyGamma(GX_GM_1_0);

	// setup the vertex descriptor
	// tells the flipper to expect direct data
	GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_F32, 0);
	GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);

	GX_SetNumChans(1);
	GX_SetNumTexGens(1);
	GX_SetTevOp(GX_TEVSTAGE0, GX_REPLACE);
	GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
	GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
}

void video_init()
{
	VIDEO_Init();

	vmode = VIDEO_GetPreferredMode(NULL);

	// Widescreen fix
	screenHeight = vmode->xfbHeight;
	if(CONF_GetAspectRatio() == CONF_ASPECT_16_9) screenWidth = screenHeight*16/9;
	else                                          screenWidth = vmode->fbWidth;
	
	VIDEO_Configure(vmode);
	
	// Allocate 2 video buffers for double buffering
	xfb[0] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(vmode));
	xfb[1] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(vmode));
	
	// Clear framebuffers, etc.
	VIDEO_ClearFrameBuffer (vmode, xfb[0], COLOR_BLACK);
	VIDEO_ClearFrameBuffer (vmode, xfb[1], COLOR_BLACK);
	VIDEO_SetNextFramebuffer(xfb[whichbuffer]);
	VIDEO_SetBlack(FALSE);
	VIDEO_Flush();
	VIDEO_WaitVSync();
	if(vmode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync();

	video_gx_init();
	// Finally, the video is up and ready for use :)
}

int video_set_mode(s_videomodes videomodes)
{
	float texScaleX, texScaleY;
	
	GX_InvalidateTexAll();
	textureWidth = videomodes.hRes;
	textureHeight = videomodes.vRes;
	textureMem = memalign(32, GX_GetTexBufferSize(textureWidth, textureHeight, pixelformat==PIXEL_32?GX_TF_RGBA8:GX_TF_RGB565, 0, 0));

	guOrtho(perspective,0,479,0,639,0,300);
	GX_LoadProjectionMtx(perspective, GX_ORTHOGRAPHIC);

	// Determine x and y scale factors
	texScaleX = (float)screenWidth / textureWidth;
	texScaleY = (float)screenHeight / textureHeight;
	if(texScaleX < texScaleY)       texScaleY = texScaleX;
	else if (texScaleY < texScaleX) texScaleX = texScaleY;

	// Determine on-screen dimensions
	scaledWidth = (int)(textureWidth * texScaleX);
	scaledHeight = (int)(textureHeight * texScaleY) / yscale;

	// Determine offsets
	xOffset = (screenWidth-scaledWidth) / 2;
	yOffset = (vmode->efbHeight-scaledHeight) / 2;

	// Compensate for widescreen displays
	if(CONF_GetAspectRatio() == CONF_ASPECT_16_9)
	{
		scaledWidth = scaledWidth*3/4;
		xOffset = xOffset*3/4;
	}

	return 1;
}

void video_clearscreen()
{
	GXColor background = { 0, 0, 0, 0xff };
	GX_SetCopyClear (background, 0x00ffffff);
}

void vga_vwait(void)
{
	VIDEO_WaitVSync();
}

void vga_setpalette(unsigned char* pal)
{
	int i;
	for(i=0;i<256;i++)
	{
		palette = (pal[0]>>3<<11) | (pal[1]>>2<<5) | (pal[2]>>3);
		pal+=3;
	}
}

/*********** Code to actually write the image data to the screen *************/
void drawSpriteTex(int x, int y, int width, int height)
{
	GX_Begin(GX_QUADS, GX_VTXFMT0, 4);			// Draw A Quad
		GX_Position2f32(x, y);					// Top Left
		GX_TexCoord2f32(0.0, 0.0);
		GX_Position2f32(x+width-1, y);			// Top Right
		GX_TexCoord2f32(1.0, 0.0);
		GX_Position2f32(x+width-1, y+height-1);	// Bottom Right
		GX_TexCoord2f32(1.0, 1.0);
		GX_Position2f32(x, y+height-1);			// Bottom Left
		GX_TexCoord2f32(0.0, 1.0);
	GX_End();									// Done Drawing The Quad
}

inline void Set_RGB565Pixel(int x, int y, u16 color)
{
	u8 *truc = (u8*) textureMem;
	u32 offset;
	
	offset = (((y >> 2) << 3) * textureWidth) + ((x >> 2) << 5) + (((y % 4 << 2) + x % 4) << 1);
	
	*(truc + offset) = (color >> 8) & 0xFF;
	*(truc + offset + 1) = color & 0xFF;
}

inline void Set_RGBAPixel(int x, int y, u32 color)
{
	u8* truc = (u8*) textureMem;
	u32 offset;

	offset = (((y >> 2) << 4) * textureWidth) + ((x >> 2) << 6) + (((y % 4 << 2) + x % 4) << 1);

	*(truc + offset) = color & 0xFF;
	*(truc + offset + 1) = (color >> 24) & 0xFF;
	*(truc + offset + 32) = (color >> 16) & 0xFF;
	*(truc + offset + 33) = (color >> 8) & 0xFF;
}

void copyscreen8(s_screen* src)
{
	u16 x, y;
	u8* data = (u8*)src->data;
	for(y=0; yfbWidth, vmode->efbHeight, 0, 1);
	GX_InvVtxCache();
	GX_InvalidateTexAll();

	GX_ClearVtxDesc();
	GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
	GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);

	switch(pixelformat)
	{
		case PIXEL_8:
		case PIXEL_x8:
			copyscreen8(src);
			GX_InitTexObj (&texObj, textureMem, textureWidth, textureHeight, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE);
			break;
		case PIXEL_16:
			copyscreen16(src);
			GX_InitTexObj (&texObj, textureMem, textureWidth, textureHeight, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE);
			break;
		case PIXEL_32:
			copyscreen32(src);
			GX_InitTexObj (&texObj, textureMem, textureWidth, textureHeight, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
	}
	GX_LoadTexObj(&texObj, GX_TEXMAP0);

	guMtxIdentity(GXmodelView2D);
	guMtxTransApply (GXmodelView2D, GXmodelView2D, 0.0F, 0.0F, 0.0F);
	GX_LoadPosMtxImm(GXmodelView2D, GX_PNMTX0);

	drawSpriteTex(xOffset, yOffset/yscale, scaledWidth, scaledHeight);
	GX_DrawDone();

	GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
	GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
	GX_SetAlphaUpdate(GX_TRUE);
	GX_SetColorUpdate(GX_TRUE);
	GX_CopyDisp(xfb[whichbuffer],GX_TRUE);

	VIDEO_SetNextFramebuffer(xfb[whichbuffer]);
	VIDEO_Flush();
	VIDEO_WaitVSync();
	whichbuffer ^= 1;		// flip framebuffer

	return 1;
}

Anyone know what's going on?
Re: GX issue
May 22, 2010 09:22AM
What if you changed this:

	GX_CopyDisp(xfb[whichbuffer],GX_TRUE);

	VIDEO_SetNextFramebuffer(xfb[whichbuffer]);
	VIDEO_Flush();
	VIDEO_WaitVSync();
	whichbuffer ^= 1;		// flip framebuffer

Into this:
	whichbuffer ^= 1;		// flip framebuffer
	GX_CopyDisp(xfb[whichbuffer],GX_TRUE);

	VIDEO_SetNextFramebuffer(xfb[whichbuffer]);
	VIDEO_Flush();
	VIDEO_WaitVSync();
Re: GX issue
May 22, 2010 04:09PM
Thanks, but I'm still having the same problem.
Re: GX issue
May 22, 2010 06:33PM
Never mind, I fixed it. I wasn't flushing the cache before loading a new texture. I solved the problem by calling DCFlushRange immediately before calling GX_LoadTexObj.
Sorry, only registered users may post in this forum.

Click here to login